我按照here上的示例动态选择要在运行时注入的实现。然后我尝试根据我的理解实现它,但我的代码总是返回默认实现;
这是我的代码
@Stateless
public class MemberRegistration {
@Inject
private Logger log;
@Inject
private EntityManager em;
@Inject
private Event<Member> memberEventSrc;
@Inject
@Switch
IHandler handler;
private int handlerValue;
public String testCDI(int value) {
handlerValue = value;
log.info("handling " + value);
log.info("handling " + handlerValue);
return handler.handle();
}
@Produces
@RequestScoped
@Switch
public IHandler produceHandler(@New Handler0 handler0,
@New Handler1 handler1) {
log.info("Calling producer method with handler: "+handlerValue);
switch (handlerValue) {
case 1:
log.info("returning one");
return handler1;
case 0:
log.info("returning 0");
return handler0;
default:
log.info("returning default");
return handler1;
}
}
}
当我调用方法testCDI
时,我会更新handlerValue
,以便我的生产者方法可以使用该值。我在这里缺少什么来确保在正确的值可用时调用生产者方法?
代码在Wildfly 8.2.0上运行
答案 0 :(得分:0)
当您调用该方法时,注入的实例不会被解析,但是在注入bean时(在这种情况下是无状态会话bean)。因此,handlerValue将为0.
但是,您可以使用Instance<IHandler>
来延迟注射。使用注释文字而不是开关来执行类似
@Inject
@Any
private Instance<IHandler> handlerInst
然后在你的代码中
IHandler handler = handlerInst.select(new SwitchLiteral(value)).get();
然后对那个人起作用,但是在你的制作人中你需要使用InjectionPoint
类来阅读Switch
所代表的SwitchLiteral
注释
答案 1 :(得分:0)
您正在使用简化代码遇到循环依赖。注入普通@Inject
的字段需要在创建MemberRegistration
之前解析,但处理程序字段只能使用生成器方法创建AFTER MemberRegistration
创建(生成器方法的bean根据与其他CDI bean相同的规则。)
有两种解决方案:
您要创建一个单独的HandlerProducer
类,其中包含produceHandler()
方法和也 handlerValue
字段。您应该将该类标记为@ApplicationScoped
,以便重复使用相同的实例。
或者您不仅需要动态生成IHandler,还需要在MemberRegistration
中真正需要时动态使用(注入它) - 这样就可以在创建MemberRegistration
之前生成处理程序,但之后或从未如果不需要。您可以通过注入Instance对象然后使用其get()方法在需要时检索处理程序来完成此操作。无论如何,我不确定CDI每次都会创建一个新实例,还是重用现有的EJB。 EJB和普通CDI bean的范围完全不同,一般来说,我不会将EJB用作生成器方法的bean。最好始终为生产者方法创建一个单独的bean,如解决方案1中所示。
解决方案2的示例如下:
@Inject
@Switch
Instance<IHandler> handlerInjector;
private int handlerValue;
public String testCDI(int value) {
handlerValue = value;
log.info("handling " + value);
log.info("handling " + handlerValue);
return handlerInjector.get().handle();
}