带实例的 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 以注入一个。 MyInterfaceImpl1MyInterfaceImpl2MyInterfaceImpl3 都是合法的 bean,可以在应用程序的任何位置注入。如果这些 bean 很重,创建可能需要一些时间,而且可能无法将它们注入任何地方?然后是您的生产者方法 - 第四个 bean - 我认为它最终是您所追求的唯一方法。

其次,三个实现bean与生产者方法的作用域不同。如果他们有资格注入,在你的情况下,他们共享相同的范围似乎合乎逻辑?

第三,使用@Singleton。我还建议 @ApplicationScoped,使用代理没有任何害处和开销。使用 CDI 单例(它的行为不像 EJB 单例)时,您将无法区分它们并且可以轻松避免一些令人不快的意外。