【发布时间】:2013-10-07 12:39:07
【问题描述】:
这可能吗:
@Inject
@MessageTransport(MessageTransportType.SMS)
public static MessageSender messageSender;
当我试图访问这个静态变量时,我得到了一个 NPE。所以我想知道,如果一般来说是不可能的。
提前致谢。
【问题讨论】:
标签: jakarta-ee cdi
这可能吗:
@Inject
@MessageTransport(MessageTransportType.SMS)
public static MessageSender messageSender;
当我试图访问这个静态变量时,我得到了一个 NPE。所以我想知道,如果一般来说是不可能的。
提前致谢。
【问题讨论】:
标签: jakarta-ee cdi
目前不可能,但理论上也不是不可能。
另一个答案表明这是不可能的,但解释描述了 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。
【讨论】:
一般不会这样做,因为静态变量不能有范围,即它只是整个类(读取应用程序)的一个,因此它没有意义,因为每个实例都会尝试将其设置为基于当前范围。
【讨论】:
显然您不应该这样做,但有时我认为您必须这样做,因为有时某些库中存在由其他东西实例化的对象(例如使用ServiceLoader),您想注入它们。这是你可以做的一个技巧:
class StaticallyInjected {
private static MyBean bean;
void inject (@Observes @Initialized (ApplicationScoped.class) Object x,
MyBean bean) {
StaticallyInjected.bean = bean;
}
}
【讨论】:
Object x 在这里做什么?