【问题标题】:Spring @PostConstruct vs. init-method attributeSpring @PostConstruct 与 init-method 属性
【发布时间】:2011-12-15 11:15:04
【问题描述】:

在Spring XML配置中使用@PostConstruct注解和声明与init-method相同的方法有什么区别吗?

【问题讨论】:

    标签: spring


    【解决方案1】:

    实际上,我认为没有任何区别,但它们的工作方式有优先级。 @PostConstructinit-method 是 BeanPostProcessor。

    1. @PostConstruct 是 JSR-250 注释,而 init-method 是 Spring 的初始化方法。
    2. 如果您有一个@PostConstruct 方法,它将在调用初始化方法之前首先被调用。
    3. 如果您的 bean 实现 InitializingBean 并覆盖 afterPropertiesSet,则首先调用 @PostConstruct,然后调用 afterPropertiesSet,然后再调用 init-method

    有关更多信息,您可以查看 Spring 的reference documentation

    在 JSR 250 规范之前,在 xml 中使用 init-method 是首选方式,因为它将 java 类(bean)与任何 spring 特定类/注释分离。因此,如果您正在构建一个不需要依赖的库spring 基础设施 bean 则首选使用 init-method。在创建方法期间,您可以指定需要调用的方法作为初始化方法。

    现在随着 Java EE 中 JSR 250 规范的引入和 spring 对这些注解的支持,在一定程度上减少了对 spring 框架的依赖。

    但我不得不承认,添加这些东西会增加代码的可读性。所以这两种方法各有利弊。

    【讨论】:

    • 如果一个 bean 使用多个这些方法并依赖于初始化的顺序,那么它将会非常复杂且无法维护。
    • @Donal 非常正确。只是提供有关其工作原理的信息。
    • 有一个重要的区别:你需要专门配置Spring来处理注解才能让@PostConstruct工作:stackoverflow.com/q/3434377/134898
    • @DonalFellows,但如果您打算参加认证考试,则需要知道这一点;)
    • @DonalFellows - 你能详细说明你的答案吗?我的意思是如果一个 bean 依赖于初始化顺序所面临的困难。其实我想知道哪个更好。 PostConstruct 或 Bean(initMethod="init") 在 bean 服务任何请求之前从 bean 做一些初始化工作?
    【解决方案2】:

    完整代码在这里:https://github.com/wkaczurba/so8519187 (spring-boot)

    使用注释:

    @Slf4j
    @Component
    public class MyComponent implements InitializingBean {
    
        @Value("${mycomponent.value:Magic}")
        public String value;
    
        public MyComponent() {
            log.info("MyComponent in constructor: [{}]", value); // (0) displays: Null
        }
    
        @PostConstruct
        public void postConstruct() {
            log.info("MyComponent in postConstruct: [{}]", value); // (1) displays: Magic
        }
    
        @Override // init-method; overrides InitializingBean.afterPropertiesSet()
        public void afterPropertiesSet() {
            log.info("MyComponent in afterPropertiesSet: [{}]", value);  // (2) displays: Magic
        }   
    
        @PreDestroy
        public void preDestroy() {
            log.info("MyComponent in preDestroy: [{}]", value); // (3) displays: Magic
        }
    }
    

    得到我们:

    正在刷新 org.springframework.context...

    构造函数中的 MyComponent:[null]
    postConstruct 中的 MyComponent:[Magic]
    afterPropertiesSet 中的 MyComponent:[Magic]
    ...

    在启动时为 JMX 公开注册 bean
    0.561 秒内启动 DemoApplication(JVM 运行 1.011)
    正在关闭 org.springframework.context... 在关闭时取消注册 JMX 公开的 bean

    ...
    preDestroy 中的 MyComponent:[Magic]

    【讨论】:

      【解决方案3】:

      没有真正的区别。这取决于您喜欢如何配置系统,这是个人选择的问题。我自己,我更喜欢为我自己的代码使用@PostConstruct 注释(因为只有在调用方法后才正确配置 bean)并且我在从非 Spring 感知库实例化 bean 时使用init-method(不能应用注释那里,当然!)但我完全可以理解人们想要以一种或另一种方式做到这一点。

      【讨论】:

        【解决方案4】:

        @postconstruct 不是弹簧的一部分。它是 javax 包的一部分。两者都是一样的。使用 init-method 我们需要在 xml 文件中添加。如果您使用 @postconstruct,则不需要在 xml 中添加。看看下面的文章。

        http://answersz.com/spring-postconstruct-and-predestroy/

        【讨论】:

          【解决方案5】:

          如下图所示Bean Creation Life-Cycle Callback

          这 3 个步骤发生在 Bean 创建生命周期回调中:

          1. 提到会调用@PostConstruct
          2. 如果实现了InitializingBean,则将调用afterPropertiesSet()
          3. 如果 bean 定义包含 init-method@Bean(initmethod="..") 则调用 init 方法。

          这张图来自Pro Spring 5: An In-Depth Guide to the Spring Framework and Its Tools

          【讨论】:

            【解决方案6】:

            @PostConstructinit-method 之间可能存在差异,因为 @PostConstruct 在 bean 初始化(AbstractAutowireCapableBeanFactory.initializeBean() 方法)的 postProcessAfterInitialization 阶段由 CommonAnnotationBeanPostProcessor 处理,而 @ 987654327@ 方法在postProcessBeforeInitialization 阶段完成后被调用(就此而言,在postProcessAfterInitialization 阶段开始之前)。
            编辑: 所以,顺序是: 1)postProcessBeforeInitialization阶段, 2) init 方法被调用, 3)postProcessAfterInitialization阶段,调用@PostConstruct方法

            (作为旁注,来自已接受答案的声明

            @PostConstruct,init-method 是 BeanPostProcessors

            不太正确:@PostConstructBeanPostProcessor 处理,init 方法不是。)

            如果某些(可能是自定义的)BeanPostProcessor(配置为(Ordered.getOrder())在CommonAnnotationBeanPostProcessor 之后执行)在其postProcessBeforeInitialization 中做一些严肃的事情,会有差异方法。
            BeanPostProcessors的默认Spring配置没有任何区别,因为所有配置为在CommonAnnotationBeanPostProcessor之后执行的BeanPostProcessors,在postProcessBeforeInitialization方法中不做任何事情。

            总之,公认的答案和类似的答案都是对的……在99%的情况下,这篇文章只是为了致敬“细节中的魔鬼”这个概念

            【讨论】:

            • 嗨!这很令人困惑,如果 PostConstruct 在 init-method 之前运行,如果 init 方法在 postProcessBeforeInitialization 之后和 postProcessAfterInitialization 之前运行,那么 postProcessAfterInitialization 是如何处理的???
            • @Maxrunner,很抱歉造成混乱,非常感谢您的告知!事实上,我从来没有说 PostConstruct 在 init-method 之前运行。无论如何,我用一些澄清更新了我的答案
            猜你喜欢
            • 2012-07-07
            • 2016-02-10
            • 1970-01-01
            • 2011-02-18
            • 1970-01-01
            • 1970-01-01
            • 2012-03-11
            • 1970-01-01
            相关资源
            最近更新 更多