我有必要在运行时提供正确的Bean实现。
常用界面:
public interface MyInterface { ... }
实现:
@Named("one")
class MyInterfaceImpl1 implements MyInterface { ... }
@Named("two")
class MyInterfaceImpl2 implements MyInterface { ... }
@Named("three")
class MyInterfaceImpl3 implements MyInterface { ... }
请注意,这些类是程序包专用的。
然后我写了一个@Produces
方法:
@Produces
@Singleton
MyInterface getMyInterface(
final Instance<MyInterface> myInterfaceImplementations,
final Configuration configuration) {
// Might be one, two or three.
final String parameter = configuration.getString("value");
return myInterfaceImplementations.select(new NamedLiteral(parameter)).get();
}
这是正确的方法吗?还是有更好的解决方案?
答案 0 :(得分:1)
您的解决方案可以正常工作,这是我的0.02 $,只是为了确保您打算这样做:
Nikos Paraskevopoulos在他的评论中的意思是,您正在有效地创建四个注入一个的bean。 MyInterfaceImpl1
,MyInterfaceImpl2
,MyInterfaceImpl3
都是可在应用程序中任何位置注入的合法bean。如果这些豆很重,那么创建可能会花费一些时间,那么可能不打算将它们注入任何地方吗?然后是您的生产者方法-第四个bean-我认为最终是您所追求的唯一方法。
第二,这三个实现Bean的范围不同于生产者方法。如果他们有资格进行注射,那么在您的情况下,也许它们共享相同的范围似乎合乎逻辑?
第三,使用@Singleton
。我也建议@ApplicationScoped
,使用代理不会造成任何伤害,也不会增加开销。您将无法分辨出差异,并且可以轻松避免CDI单例(它的行为不像EJB单例)令人不快的情况。
答案 1 :(得分:0)
我认为一个更优雅的解决方案是让CDI尽一切能力;-) 像这样:
import javax.enterprise.inject.spi.CDI;
@Produces
@Singleton
MyInterface getMyInterface(final Configuration configuration) {
// Might be one, two or three.
final String parameter = configuration.getString("value");
Set<MyInterface> candidates = CDI.current().getBeanManager().getBeans(parameter);
return ( candidates.size()>0 ? candidates.get(0) : null);
}
在查找接口的特定隐式实现时,还可以使用getBeans()签名的备用签名来玩限定符: cfr https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/BeanManager.html#getBeans-java.lang.reflect.Type-java.lang.annotation.Annotation...-