带实例的 CDI 条件 Bean<T>
CDI conditional Bean with Instance<T>
我有必要在运行时提供正确的 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();
}
这是正确的方法,还是有更好的解决方案?
我认为一个更优雅的解决方案是让 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...-
你的解决方案会很好用,这是我的 0.02 美元,只是为了确保你是这样想的:
Nikos Paraskevopoulos 在他的评论中的意思是您正在有效地创建四个 bean 以注入一个。 MyInterfaceImpl1
、MyInterfaceImpl2
、MyInterfaceImpl3
都是合法的 bean,可以在应用程序的任何位置注入。如果这些 bean 很重,创建可能需要一些时间,而且可能无法将它们注入任何地方?然后是您的生产者方法 - 第四个 bean - 我认为它最终是您所追求的唯一方法。
其次,三个实现bean与生产者方法的作用域不同。如果他们有资格注入,在你的情况下,他们共享相同的范围似乎合乎逻辑?
第三,使用@Singleton
。我还建议 @ApplicationScoped
,使用代理没有任何害处和开销。使用 CDI 单例(它的行为不像 EJB 单例)时,您将无法区分它们并且可以轻松避免一些令人不快的意外。
我有必要在运行时提供正确的 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();
}
这是正确的方法,还是有更好的解决方案?
我认为一个更优雅的解决方案是让 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...-
你的解决方案会很好用,这是我的 0.02 美元,只是为了确保你是这样想的:
Nikos Paraskevopoulos 在他的评论中的意思是您正在有效地创建四个 bean 以注入一个。 MyInterfaceImpl1
、MyInterfaceImpl2
、MyInterfaceImpl3
都是合法的 bean,可以在应用程序的任何位置注入。如果这些 bean 很重,创建可能需要一些时间,而且可能无法将它们注入任何地方?然后是您的生产者方法 - 第四个 bean - 我认为它最终是您所追求的唯一方法。
其次,三个实现bean与生产者方法的作用域不同。如果他们有资格注入,在你的情况下,他们共享相同的范围似乎合乎逻辑?
第三,使用@Singleton
。我还建议 @ApplicationScoped
,使用代理没有任何害处和开销。使用 CDI 单例(它的行为不像 EJB 单例)时,您将无法区分它们并且可以轻松避免一些令人不快的意外。