是否可以将CDI Bean注入Java EE 6中的静态变量?

时间:2013-10-07 12:39:07

标签: java-ee cdi

这可能吗:

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

当我尝试访问此静态变量时,我正在获取NPE。所以我想知道,如果一般情况下不可能的话。

提前致谢。

3 个答案:

答案 0 :(得分:9)

目前不可能,但理论上并非不可能。

另一个答案表明这是不可能的,但是解释描述了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之外,很难准确定义何时注入静态成员。
  •   
     

然而,有几个很好的用例:

     
      
  • logger injection,
  •   
  • 注入实体类,
  •   
  • 注入具有钝化范围的对象。
  •   
     

所以我们需要在这里支持一些东西。也许这足以说:

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

有一个专门针对静态注入的开放CDI问题:CDI-51

答案 1 :(得分:5)

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

答案 2 :(得分:0)

显然你不应该这样做,但有时我认为你必须这样做,因为有时在某些图书馆中存在被其他东西(例如使用ServiceLoader)实例化的对象并且你想要注入它们。这是你可以做的黑客攻击:

class StaticallyInjected {
  private static MyBean bean;

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