如何以编程方式将 Java CDI 托管 bean 注入(静态)方法中的局部变量
Posted
技术标签:
【中文标题】如何以编程方式将 Java CDI 托管 bean 注入(静态)方法中的局部变量【英文标题】:How to programmatically inject a Java CDI managed bean into a local variable in a (static) method 【发布时间】:2014-09-08 00:41:46 【问题描述】:如何以编程方式将 Java CDI 1.1+ 托管 bean 注入静态方法中的局部变量?
【问题讨论】:
【参考方案1】:注入类C
的实例:
javax.enterprise.inject.spi.CDI.current().select(C.class).get()
这在 CDI 1.1+ 中可用
【讨论】:
如果你使用CDI.current().select,你会得到一个Instance例如使用此实用程序class。您基本上必须获得 BeanManager
的实例,然后从中获取您想要的 bean(想象一下 JNDI 查找之类的东西)。
更新
您还可以使用 CDI 1.1 中提供的 CDI 实用程序类
SomeBean bean = CDI.current().select(SomeBean.class).get();
更新 2
在 CDI 2.0 中,您必须使用 BeanManager 类以编程方式获取 bean 实例。
【讨论】:
感谢您的建议。我实际上找到了一个更简单的解决方案,我将在回复帖子中详细说明。 CDI 类只需一个简单的步骤就可以很好地做到这一点。【参考方案3】:@BRS
import javax.enterprise.inject.spi.CDI;
...
IObject iObject = CDI.current().select(IObject.class, new NamedAnnotation("iObject")).get();
与:
import javax.enterprise.util.AnnotationLiteral;
public class NamedAnnotation extends AnnotationLiteral<Named> implements Named
private final String value;
public NamedAnnotation(final String value)
this.value = value;
public String value()
return value;
【讨论】:
所以,在为带有Named注解值iObject的IObject编写实现类之后,我们需要编写一个匿名内部类来获取实例。这不是比简单地查找和投射更复杂吗?或者如果我的理解有误请指正。 如果您实际上可以通过导入并将一步分为两步来使其更具可读性,那可能会更好。这样它就变得更具可读性。NamedAnnotation
可以用于任何@Named
bean,而不仅仅是IObject
s。 ProgrammaticBeanLookup
比NamedAnnotation
需要更多的代码,但只能用于Class
或@Named String
,而CDI
路由可以接受其他注释和/或TypeLiteral
。 ProgrammaticBeanLookup
还要求 JNDI 类位于类路径中,如果不是,则手动填充非最终静态变量。此外,BeanManager
不能保证是线程安全的,因此ProgrammaticBeanLookup
可能存在线程问题。
您始终可以将CDI
用法包装在帮助方法中,例如<T> T getNamedBean(Class<T> clazz, String name)
【参考方案4】:
@Petr Mensik 建议的链接非常有用。我在示例中使用了相同的代码。
这是一种在实例方法/静态方法中获取类实例的方法。为接口编写代码总是比在方法中使用硬编码的类名更好。
@Named(value = "iObject ")
@RequestScoped
class IObjectImpl implements IObject .....
//And in your method
IObject iObject = (IObject) ProgrammaticBeanLookup.lookup("iObject");
.........
//Invoke methods defined in the interface
当您有一个应用程序范围的对象,该对象的方法需要一个可能随时间变化的类的实例时,这种对 bean 的编程查找非常有用。因此,为了松耦合,最好提取接口并使用程序化 bean 查找。
【讨论】:
请看我的新答案,它展示了注释如何与CDI
方法一起使用,它提供比ProgrammaticBeanLookup
更通用和类型安全的查找【参考方案5】:
你应该包括限定词:
List<Annotation> qualifierList = new ArrayList();
for (Annotation annotation: C.class.getAnnotations())
if (annotation.annotationType().isAnnotationPresent(Qualifier.class))
qualifierList.add(annotation);
javax.enterprise.inject.spi.CDI.current()
.select(C.class, qualifierList.toArray(new Annotation[qualifierList.size()])
.get()
【讨论】:
【参考方案6】: 您可以定义一个参数,其中包含 bean 接口的类型 您的静态方法,并传递适当的实现参考。 这将使它对单元测试更加友好。 如果您使用的是Apache Deltaspike,则可以使用BeanProvider#getContextualReference。这比获取 javax.enterprise.inject.Instance 更容易,但是要注意依赖 bean(请参阅 javadoc)!【讨论】:
以上是关于如何以编程方式将 Java CDI 托管 bean 注入(静态)方法中的局部变量的主要内容,如果未能解决你的问题,请参考以下文章
CDI 托管 bean 和 JSF 托管 bean 可以相互通信吗?