【问题标题】:@Inject only working for POJOs created by CDI container?@Inject 仅适用于由 CDI 容器创建的 POJO?
【发布时间】:2012-08-22 19:44:04
【问题描述】:

我只是想确认我完全了解 CDI 工作的先决条件。如果我有 A 类:

public class A {
    @Inject private B b;
}

现在,当我使用以下方法实例化此类时:

A a = new A();

在这种情况下,A.b 将为空。

但是如果我在另一个类中定义一个成员:

@Inject A a;

以后使用a,a.b会正确填充吗?

CDI 是否仅在需要注入的类也由 CDI 容器创建时才有效?或者,如果在使用 new 的普通实例化创建 POJO 时注入结果为空,我会错过什么(是的,我有 beans.xml 到位)?

【问题讨论】:

    标签: java jakarta-ee java-ee-6 cdi


    【解决方案1】:

    CDI 是否仅在需要注入的类也是 由 CDI 容器创建?

    是的,差不多就是这样。 ManagedBean 的生命周期由容器控制,永远不应使用 new 关键字实例化(顺便说一句:EJB 和 Spring bean 也是如此)。如果您需要创建一个新的 ManagedBean,您可能需要使用 producer method

    【讨论】:

    • 啊,现在我开始明白为什么会有生产者方法了。
    • new 不会注入并不完全正确。你可以让new用弹簧注入:See Spring's @Configurable
    • 我希望能在春天度过并坚持使用纯 JEE6 进行 CDI。但我认为 CDI 是安静有限的。例如,如果我有一个 servlet 上下文,我不能注入任何由 CDI 管理的东西,因为 servlet 类不是由 CDI 容器创建的。我想这就是 Spring 有用的地方。
    • @sebi - 关于您对 CDI 和 servlet 容器的评论。你的理解是不正确的。您可以愉快地将 CDI bean 注入带有 JavaEE6 的 servlet。 servlet 或 servlet 过滤器是 CDI 容器的“托管”对象。这也适用于 JAX-RS / Jersey 资源,因此您也可以注入它们。您也可以将 EJB 注入 servlet。
    • @AdamGreen - 据我了解,OP 完全不知道容器接管了 bean 的生命周期。这就是为什么我仍然认为 new Foo() 对于依赖注入的 hello world 尝试不是一个好主意——尽管大多数容器(包括 CDI)都提供了解决此限制的方法。
    【解决方案2】:

    虽然其他人已经正确地指出,在大多数情况下,DI 容器不会将依赖项注入到他们没有实例化的 bean 中,但这并不完全正确。

    Spring 有一个很棒的功能,当您使用new A() 创建 bean 时,它会自动装配它。 你只需要使用AspectJ and mark your bean with the @Configurable annotation

    @Configurable
    public class A {
        @Inject private B b;
    }
    

    它实际上是一个很棒的功能,因为您可以在执行 Active Record 风格的 POJO 的同时仍然尊重您的 DI(实际上 Spring Roo 就是这样做的)。

    您还应该知道,使用 Spring 您可以在使用 AutowireCapableBeanFactory 实例化 bean 后以编程方式自动装配 bean。这就是它通常自动装配 JUnit 测试用例类的方式,因为 JUnit 创建了测试用例类。

    是的 Spring 不是 CDI,但理论上您可以为 CDI 编写自己的 @Configurable,或者可能有一种 CDI 方式来执行上述操作。

    话虽如此,上述是一种复杂的功能(也是一种黑客行为),正如@JanGroth 所提到的,理解lifecycle bean management of the container 是至关重要的,无论是它的 CDI、Spring、Guice 等。

    【讨论】:

    • 嗯,OP 询问了 CDI,最终接受的答案描述了 Spring 特性。很奇怪。 :)
    • @jangroth 我不认为我会被标记为正确。我只是提出我的答案,以防有人想用new *() 进行 DI ......我也有点猜到他真的想要那个,但也许我只是让他更困惑。你总是可以-1我的帖子:)
    • 别担心,伙计,我很高兴为你提出这个有趣的方面 +1 :)
    • 问题是几乎所有答案都是正确的。所以我选择了那个给我最多见解的那个。
    【解决方案3】:

    您可以使用Apache DeltaSpike 中的BeanProvider.injectFields(myObject);

    【讨论】:

      【解决方案4】:

      是的,@Inject 只能在容器内工作,因为它是在方法调用上使用拦截器完成的。当容器创建一个 bean 时,它会将其包装在执行注入的拦截器中,并且在使用 new 进行实例化的情况下,在 bean 方法调用期间不会调用任何拦截器,也不会进行注入。

      【讨论】:

      • 拦截器中是否发生注入?还是在容器创建 bean 时发生?我想应该是后者。如果你使用的是构造函数注入,那一定是后者。
      • 不,@Inject 不适用于拦截器 - 它适用于代理(主要是出于性能原因)。查看Weld 的优秀文档以了解完整情况。
      【解决方案5】:

      以下是类成为托管 bean 所需的条件(因此,@Inject 注释对其字段/方法起作用):

      http://docs.oracle.com/javaee/6/tutorial/doc/gjfzi.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-11
        • 1970-01-01
        • 2017-11-08
        • 2018-09-28
        相关资源
        最近更新 更多