0

我按照此处的示例动态选择在运行时注入的实现。然后我尝试根据我的理解来实现它,但我的代码总是返回默认实现;

这是我的代码

@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 上运行

4

2 回答 2

0

当您调用该方法时,注入的实例不会被解析,而是在注入 bean(在本例中为无状态会话 bean)时解析。结果,handlerValue 将为 0。

但是,您可以使用 anInstance<IHandler>来推迟注入。使用注释文字而不是您的开关来执行类似的操作

@Inject
@Any
private Instance<IHandler> handlerInst

然后在你的代码中

IHandler handler = handlerInst.select(new SwitchLiteral(value)).get();

然后对那个人做工作,但是在你的生产者中你需要使用这个InjectionPoint类来阅读SwitchSwitchLiteral

于 2015-08-30T20:53:13.887 回答
0

您在这里使用简化的代码遇到了循环依赖。注入plain的字段@Inject需要在MemberRegistration创建之前解析,但处理程序字段只能在创建后使用生产者方法MemberRegistration创建(具有生产者方法的bean根据与其他CDI bean相同的规则创建)。

有2个解决方案:

  1. 您可以创建一个单独的HandlerProducer类,该类将包含produceHandler()方法和字段。您应该将类​​标记为以便在所有地方重用相同的实例。 handlerValue@ApplicationScoped

  2. 或者您不仅需要动态生成 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();
}
于 2015-08-31T08:04:40.537 回答