具有Instance <t>的CDI条件Bean

时间:2018-10-01 18:28:58

标签: java cdi

我有必要在运行时提供正确的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();
}

这是正确的方法吗?还是有更好的解决方案?

2 个答案:

答案 0 :(得分:1)

您的解决方案可以正常工作,这是我的0.02 $,只是为了确保您打算这样做:

Nikos Paraskevopoulos在他的评论中的意思是,您正在有效地创建四个注入一个的bean。 MyInterfaceImpl1MyInterfaceImpl2MyInterfaceImpl3都是可在应用程序中任何位置注入的合法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...-