如何以编程方式将 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,使用后别忘了销毁它。 XDR,您的解决方案对我有用。我尝试了一种不同的方法,但无法正常工作: context.getApplication().evaluateExpressionGet(context, "#beanName", BeanName.class) 他们不应该都工作吗? @punchingInAPepper:我不熟悉你提到的方法,所以很遗憾,我无法回答你的问题。 @jpangamarca 破坏?你能解释一下吗? @Dherik 销毁从注入的 Instance 获得的 bean 引用是避免内存泄漏所必需的,请参阅weld.cdi-spec.org/news/2016/05/18/enhanced-instance【参考方案2】:

例如使用此实用程序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,而不仅仅是IObjects。 ProgrammaticBeanLookupNamedAnnotation 需要更多的代码,但只能用于Class@Named String,而CDI 路由可以接受其他注释和/或TypeLiteralProgrammaticBeanLookup 还要求 JNDI 类位于类路径中,如果不是,则手动填充非最终静态变量。此外,BeanManager 不能保证是线程安全的,因此ProgrammaticBeanLookup 可能存在线程问题。 您始终可以将CDI 用法包装在帮助方法中,例如&lt;T&gt; T getNamedBean(Class&lt;T&gt; 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 注入(静态)方法中的局部变量的主要内容,如果未能解决你的问题,请参考以下文章

将 JSF 托管 bean 迁移到 CDI 托管 bean

CDI 托管 bean 和 JSF 托管 bean 可以相互通信吗?

使用 CDI(上下文和依赖注入)支持 bean 而不是托管 Bean

如何以编程方式注册 JSF 托管 bean?

如何在 Quarkus 中以编程方式注册 bean?

cdi bean 中的资源注入