【问题标题】:How to programmatically inject a Java CDI managed bean into a local variable in a (static) method如何以编程方式将 Java CDI 托管 bean 注入(静态)方法中的局部变量
【发布时间】:2014-09-08 00:41:46
【问题描述】:

如何以编程方式将 Java CDI 1.1+ 托管 bean 注入静态方法中的局部变量?

【问题讨论】:

    标签: java dependency-injection cdi jboss-weld weld


    【解决方案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)!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-10-13
        • 2014-02-27
        • 1970-01-01
        • 2011-10-08
        • 2015-06-14
        • 1970-01-01
        • 1970-01-01
        • 2015-08-06
        相关资源
        最近更新 更多