【问题标题】:Spring IoC - Ensuring all beans are created before @PostConstruct/afterProperiesSetSpring IoC - 确保在 @PostConstruct/afterProperiesSet 之前创建所有 bean
【发布时间】:2013-12-19 08:32:18
【问题描述】:

我有一个使用 Spring IoC 进行依赖注入的项目,我试图通过一个中心位置来访问我的大部分 bean,从而稍微简化我的模型。

我在使用@PostConstruct 机制或实现InitializingBean 接口时遇到了问题。虽然该特定 bean 中的所有依赖关系可能都已解决,但注入 bean 中的依赖关系可能尚未解决。例如我有:

public class A {
    public void doSomething() {};
}

public class B {
    private A objectA;

    @Required
    public void setObjectA(A objectA) {
        this.objectA = objectA;
    }

    public A getObjectA() {
        return objectA;
    }
}

public class C implements InitializingBean {
    private B objectB;

    @Required
    public void setObjectB(B objectB) {
        this.objectB = objectB;
    }

    public void afterPropertiesSet() throws Exception {
        objectB.getObjectA().doSomething();
    }
}

我的 context.xml 文件定义了这三个 bean 并注入了适当的属性,但是当 C 类的对象被实例化并调用 afterPropertiesSet 方法时,我得到了 NullPointerException,调试显示对 @ 的调用987654326@ 返回null。如果我将对象 A 直接注入到类 C 中,则不会出现错误。

我是否可以使用一种机制来确保在我的 afterPropertiesSet 方法/任何带有 @PostConstruct 注释的方法被调用之前已完全实例化所有 bean?

谢谢,

约瑟夫。

【问题讨论】:

  • “虽然该特定 bean 中的所有依赖关系可能已解决,但注入 bean 中的依赖关系可能尚未解决。”是什么让你得出这个结论?在您的情况下,C 需要 B,而 B 又需要 A。因此,当创建 C 的实例时,您将拥有 B 的实例以及已经创建的 A。

标签: java spring


【解决方案1】:

afterPropertiesSet() 调用注入依赖项的方法还为时过早。实际上,在 afterPropertiesSet() 之后调用 init 方法(如果您在 XML 中有该方法),然后调用 BeanPostProcessors 的 postProcessAfterInitialization()。你有@Required 注解,所以当然会执行RequiredAnnotationBeanPostProcessor。

生命周期回调方法就是它们的本质:它们通知你生命周期事件,它们的目的不是让你劫持 Spring 正在执行的任务。 (虽然你可以像在 C 中直接注入对象 A 那样做,但不推荐这样做)。

如果您想在 C 类中使用对象 A(或任何其他 Spring bean),那么我建议使用 ApplicationContextAware(或 BeanFactoryAware,视情况而定)并使用 getBean() 方法来完全烘焙准备好上菜了!

【讨论】:

  • ApplicationContextAware.setApplicationContext() 在过程的早期被调用,在所有 bean 都被烘烤之前。
  • @ericacm 非常好的评论。我期待着它。 :) 在 afterPropertiesSet() 之前调用 setApplicationContext 是绝对正确的。所以问题是为什么 afterPropertiesSet() 太早了,而 applicationContext 的 getBean() 就可以了。它提出了很多问题。事实上,早在 7 年多前,Spring 设计师就曾争论过这个问题。请参阅osdir.com/ml/java.springframework.devel/2004-01/msg00084.html
【解决方案2】:

实现 ApplicationListener[ContextRefreshedEvent] 并在 onApplicationEvent() 中完成您的工作。注意事项 - ContextRefreshedEvent 有时会发布多次,因此您可能需要在第一次获取它后设置一个标志以忽略其他事件。

【讨论】:

  • ContextRefreshedEvent 被剥离,重新添加到方括号中。
【解决方案3】:

使用@DependsOn 确保在 C 之前实例化 A。

【讨论】:

    猜你喜欢
    • 2014-09-13
    • 2023-03-26
    • 2022-08-20
    • 2020-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-07
    相关资源
    最近更新 更多