使用Producer方法选择Bean实现

时间:2015-08-30 08:05:23

标签: interface cdi producer

我按照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上运行

2 个答案:

答案 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相同的规则。)

有两种解决方案:

  1. 您要创建一个单独的HandlerProducer类,其中包含produceHandler()方法和 handlerValue字段。您应该将该类标记为@ApplicationScoped,以便重复使用相同的实例。

  2. 或者您不仅需要动态生成IHandler,还需要在MemberRegistration中真正需要时动态使用(注入它) - 这样就可以在创建MemberRegistration之前生成处理程序,但之后或从未如果不需要。您可以通过注入Instance对象然后使用其get()方法在需要时检索处理程序来完成此操作。无论如何,我不确定CDI每次都会创建一个新实例,还是重用现有的EJB。 EJB和普通CDI bean的范围完全不同,一般来说,我不会将EJB用作生成器方法的bean。最好始终为生产者方法创建一个单独的bean,如解决方案1中所示。

  3. 解决方案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();
    }