InitializingBean、BeanPostProcessor、init-method、@PostConstruct执行先后顺序
一、理论@PostConstruct 注解好多人以为是Spring提供的。其实是Java自己的注解。该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。通常我们会是在Spring框架中使用到@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 到底是谁先执行的呢?
整理后,简单逻辑如下图:
-
Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
-
Bean实例化后对将Bean的引入和值注入到Bean的属性中
-
如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
-
如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
-
如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
-
如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
-
如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
-
如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
-
此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
-
如果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的先后顺序为
- BeanPostProcessor的postProcessBeforeInitialization方法
- 注解了 @PostConstruct 的方法
- InitializingBean的afterPropertiesSet方法
- bean的指定的初始化方法: init-method
- BeanPostProcessor的postProcessAftrInitialization方法
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)