InitializingBean、BeanPostProcessor、init-method、@PostConstruct执行先后顺序

一、理论

        @PostConstruct 注解好多人以为是Spring提供的。其实是Java自己的注解。该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。通常我们会是在Spring框架中使用到@PostConstruct注解 该注解的方法在整个Bean初始化中的执行顺序:Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)。

        而 InitializingBean、BeanPostProcessor、init-method 就全都是Spring体系中的,要想搞清楚执行的先后顺序,首先要了解Spring中对 Java Bean生命周期的管理。

        在传统的Java应用中,bean的生命周期很简单,使用Java关键字 new 进行Bean 的实例化,然后该Bean 就能够使用了。一旦bean不再被使用,则由Java自动进行垃圾回收。

        相比之下,Spring管理Bean的生命周期就复杂多了,正确理解Bean 的生命周期非常重要,因为Spring对Bean的管理可扩展性非常强,下面详细介绍下一个Bean的构造过程。

Bean 的完整生命周期:

        根据上图,得到我们标题中的问题,InitializingBean、BeanPostProcessor、init-method 到底是谁先执行的呢?

        整理后,简单逻辑如下图:

  1. Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化

  2. Bean实例化后对将Bean的引入和值注入到Bean的属性中

  3. 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法

  4. 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入

  5. 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。

  6. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。

  7. 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用

  8. 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。

  9. 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。

  10. 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。

二、实践

InitializingBean

        InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。

@PostConstruct

    在类中的方法上加上注解@PostConstruct后,初始化bean的前会调用被注解的方法

package com.wzz.test.demo.springDemo;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

@Service
public class MyServiceImpl implements MyService, InitializingBean{

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet method: myServiceImpl");
    }

    @PostConstruct
    public void postConstructMethod() {
        System.out.println("PostConstruct method: myServiceImpl");
    }

    private void init() {
        System.out.println("init method: myServiceImpl");
    }
}

 bean的init-method方法

        可以在Configuration 中指定方法,也可以在Spring的xml配置文件中指定,我选择前者。

@Configuration
public class MyConfiguration {

    @Bean(initMethod="init")
    public MyServiceImpl myService(){
        return new MyServiceImpl();
    }

}

BeanPostProcessor 

        BeanPostProcessor接口提供了初始化bean时的前置接口和后置接口,我们只需要实现BeanPostProcessor中对应的接口就可以bean初始化前后做自己的逻辑处理。(BeanPostProcessor的前置和后置方法会在每个bean初始化的时候调用)

package com.wzz.test.demo.springDemo;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class MyPostProcessorBean implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor Before init: " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor after init: " + beanName);
        return bean;
    }
}

        我使用SpringBoot框架,将上面的类创建出来,启动项目,即可看到 MyServiceImpl 类的初始化过程,结论如下。 

三、结论

由此可见初始化Bean的先后顺序为

  1. BeanPostProcessor的postProcessBeforeInitialization方法
  2. 注解了 @PostConstruct 的方法
  3. InitializingBean的afterPropertiesSet方法
  4. bean的指定的初始化方法: init-method
  5. BeanPostProcessor的postProcessAftrInitialization方法
     
  • 8
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值