【问题标题】:Is it possible to inject a CDI Bean into a static variable in Java EE 6?是否可以将 CDI Bean 注入 Java EE 6 中的静态变量?
【发布时间】:2013-10-07 12:39:07
【问题描述】:

这可能吗:

@Inject
@MessageTransport(MessageTransportType.SMS)
public static MessageSender messageSender;

当我试图访问这个静态变量时,我得到了一个 NPE。所以我想知道,如果一般来说是不可能的。

提前致谢。

【问题讨论】:

    标签: jakarta-ee cdi


    【解决方案1】:

    目前不可能,但理论上也不是不可能。

    另一个答案表明这是不可能的,但解释描述了 Seam 2 中注入的工作方式。我将尝试从记忆中描述它。一些伪代码:

    @Name("a")
    class A() {
        @In
        B b;
    
        void something() {
            b.doTheThing();
        }
    }
    

    Seam 2 支持通过 BijectionInterceptor 进行注入。为了让拦截器工作,Seam 创建了组件的代理实例。这里,当a.something方法被调用时,它会被拦截,代理的b实例确实会被注入到a的实例字段b中。如果B所在的上下文在那一刻没有激活,那么注入就会失败,a.something的方法调用也会失败。

    现在让我们看一下 CDI 的类似示例:

    class A() {
        @Inject
        B b;
    
        void something() {
            b.doTheThing();
        }
    }
    

    在 CDI 中仍有代理。但注射的方式不同。 CDI 引入了上下文引用的概念。它存储在a.b 字段中。当a.something 被调用时,不会发生任何有趣的事情。在任何情况下都可能没有B 实例,并且a.something 方法仍然可以正常调用。但是在调用b.doTheThing 方法时,CDI 开始寻找实际的B 实例。例如,那时就有可能获得ContextNotActiveException

    所以这似乎是可能的。我在旧的 Weld 站点找到了 some interesting notes,这可以解释为什么尚未实施:

    静态注入

    静态成员的注入有几个问题:

    • 一个类可以在多个应用程序之间共享,Java EE 规范没有为此定义规则。
    • 在 Java EE 之外,很难准确定义何时注入静态成员。

    尽管如此,有几个很好的用例:

    • 记录器注入,
    • 实体类的注入,以及
    • 注入到具有钝化作用域的对象中。

    所以我们确实需要在这里支持一些东西。也许这样说就足够了:

    • 共享库中没有静态注入,并且
    • 在实例化 bean 的第一个实例之前注入静态字段(但非 bean 类不支持静态注入)。

    有一个专门针对静态注入的未解决 CDI 问题:CDI-51

    【讨论】:

    • 这是一个非常好的答案。只是想说明您可能想要这样做的另一个原因。如果您正在迁移旧版应用程序,您可以使用静态注入来帮助减轻从静态到 DI 转换的痛苦。
    • Stuart Douglas 关于 CDI 注入方法的帖子:developer.jboss.org/blogs/stuartdouglas/2010/10/12/…
    • @VsevolodGolovanov 不错的文章,但没有提到静态注入。
    • 我在 cmets 中提到了 Stuart Douglas 的文章,作为主题“CDI 注入的工作方式”的后续文章。 (Google cache mirror of Stuart Douglas's post.)
    【解决方案2】:

    一般不会这样做,因为静态变量不能有范围,即它只是整个类(读取应用程序)的一个,因此它没有意义,因为每个实例都会尝试将其设置为基于当前范围。

    【讨论】:

      【解决方案3】:

      显然您不应该这样做,但有时我认为您必须这样做,因为有时某些库中存在由其他东西实例化的对象(例如使用ServiceLoader),您想注入它们。这是你可以做的一个技巧:

      class StaticallyInjected {
        private static MyBean bean;
      
        void inject (@Observes @Initialized (ApplicationScoped.class) Object x,
                     MyBean bean) {
          StaticallyInjected.bean = bean;
        }
      }
      

      【讨论】:

      • Object x 在这里做什么?
      • 我从不费心去查看它的实际类型。这个想法是搭载应用程序范围初始化,这是注释所做的。我猜这是代表您的应用程序的某种对象,可能取决于 CDI 实现
      猜你喜欢
      • 1970-01-01
      • 2013-06-30
      • 1970-01-01
      • 2015-07-29
      • 2014-09-08
      • 1970-01-01
      • 1970-01-01
      • 2018-06-22
      • 2011-10-15
      相关资源
      最近更新 更多