Java EE接口条件注入

3

我有以下接口:

public interface ResultEvaluationInterface {
    public void evaluateResults(Event e);
}

我希望能够根据Event.type注入不同的类,但这些类具有相同的实现。例如:

@Stateless
@LocalBean    
public class ResultEvaluation implements ResultEvaluationInterface {

    @Override
    public void evaluateResults(Event e) {
        switch (e.getType()) {
            case Type.Running:
               // inject and call ResultEvaluationRunningEJB.evaluateResults(e)
            case Type.Swimming:
               // inject and call ResultEvaluationSwimmingEJB.evaluateResults(e)
            default:
               throw new UnsupportedOperationException("Not supported yet.");
        }
    }

}

ResultEvaluationRunningEJBResultEvaluationSwimmingEJB都实现了该接口。有没有好的方法来优雅地解决这个问题?


你是想在开发环境中使用一个开发模拟实现吗? - dngfng
“Production”和“Development”是否指的是您部署的实例,即您是否有一个仅接收“Production”事件的生产实例,或者一个安装实例是否可以同时接收“Deployment”和“Production”事件? - user140547
类型只是一个例子。我会更改它们,以免让您感到困惑。 - perotom
1
你必须使用EJB吗?还是CDI也可以选择?CDI具有事件系统,可能对您的用例有用。请参见http://docs.oracle.com/javaee/7/tutorial/cdi-adv005.htm#GKHIC - user140547
2个回答

2
如果您真的想使用硬编码的if语句来在生产环境和开发环境之间切换事件,您可以使用CDI Qualifiers将两个实现注入到Facade中:
@Stateless
@LocalBean    
public class ResultEvaluationFacade {

    @Inject
    @Development
    private ResultEvalutationInterface dev;

    @Inject
    @Production
    private ResultEvalutionInterface prod;

    @Override
    public void evaluateResults(Event e) {
        switch (e.getType()) {
            case Type.Production:
               prod.evaluteResult(e);
               break;
            case Type.Development:
               dev.evaluteResult(e);
               break;
            default:
               throw new UnsupportedOperationException("Not supported yet.");
        }
    }

}

定义两种实现:

@Development
public class ResultEvaluationDevelopment implements ResultEvaluationInterface {
   ...
}

@Production
public class ResultEvaluationDevelopment implements ResultEvaluationInterface {
   ...
}

然而,我建议使用一个模拟Maven项目来存放这两个独立的实现。

或者你可以使用不同的CDI事件类型,像这样。

public void observeDevEvent(@Observe DevEvent event) {
   //do stuff.
}

public void observeProdEvent(@Observe ProdEvent event) {
   //do stuff
}

触发事件的代码如下所示:

@Inject
private Event<ProdEvent> prodEvent;

public void someMethod() {
   ProdEvent pe = new ProdEvent()
   // set some data on ProdEvent
   prodEvent.fire(pe);
}

注意事件也可以与限定符一起使用,因此您可以向事件添加Qualifier注释,而无需实现两种不同类型的事件。

@Inject
@Production
private Event<MyEvent> event;

同时监听 @Prodcution 事件;

public void handleProdEvent(@Observer @Production MyEvent myEvent) {
    // do Stuff.
}

对于懒加载Bean,您可以使用CDI Instance注入。

@Inject
private Instance<BeanA> beanA;

....

public void doStuff(Event e) {
   ...
   case Type.Production:
            //lazily evaluates and instantiatiates bean.
            beanA.get().evaluateResult(e);
}

我认为你的第一个例子完全符合我的要求,只有一个问题:如果我添加更多的注入bean到该接口中(20-30个),并将其添加到ResultEvaluationFacade中,那么对于性能来说不会很糟糕吗?特别是如果我在例如ResultEvaluationDevelopment中使用PostConstruct事件与数据库交互。 - perotom
1
在这种情况下,我不会采用这种技术。为了解决性能问题,您可以使用Instance<BeanA>,这有效地允许对bean进行延迟加载和初始化。请参阅我的详细答案。 - dngfng
你会使用哪种技术?非常有帮助的答案! - perotom
有几个解决方案可供选择,我将在另一个答案中概述另一种解决方案。 - dngfng

0
注意:我尚未确认这是否有效,但您应该能够通过此解决方案解决问题。
您可以使用动态CDI事件分派:
public class EventDispatcher {

    @Inject
    BeanManager beanManager;

    public void handle(MyEvents mytype) {
        beanManager.fireEvent(mytype, mytype.getQualifiyer());
    }
}

您可以像以下这样在事件枚举中引用限定符:

public enum MyEvents {

    EVENTA(new EventA() {
        @Override
        public Class<? extends Annotation> annotationType() {
            return this.getClass();
        }
    }),
    EVENTB (new EventB() {
        @Override
        public Class<? extends Annotation> annotationType() {
            return this.getClass();
        }
    });

    private final Annotation annotation;

    MyEvents(Annotation annotation) {
        this.annotation = annotation;
    }
    public Annotation getQualifiyer() {
        return annotation;
    }

};

限定符大致如下:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER,ElementType.FIELD})
public @interface EventA {

}

那样,您可以将观察者方法简单地添加到事件处理的bean中:
public class EventProcessorA {
   ...
   public void handleEvent(@Observer @BeanA MyEvents myevent) {
       ...
   }
}

不要在一个调度程序中使用巨大的switch语句注入20-30个。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接