1、Spring Bean 生命周期整体流程

Spring Bean 的生命周期,概括起来主要有四个阶段:

  1. 实例化(Instantiation):基于BeanDefinition实例化一个 Bean ,此时 Bean 里的属性字段为 null 尚未赋值;
  2. 属性赋值(Populate):为 Bean 里的属性字段赋值,包括解析@Autowired等注入的属性字段;
  3. 初始化(Initialization):将属性赋值后的 Bean 注册到 Spring 容器中,这里 Spring 提供了很多拓展接口,支持用户自定义 Bean 的初始化过程中做哪些操作,具体接口在第3小节介绍;
  4. 销毁(Destruction):销毁 Bean ,通常在 Spring 应用结束时调用。

Bean的生命周期 - 图1

2、面试说辞

Bean的生命周期 - 图2

Bean 生命周期的整个执行过程描述如下:

  1. Spring 启动,查找并加载需要被 Spring 管理的 Bean,对 Bean 进行实例化。
  2. 对 Bean 进行属性注入。
  3. 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。
  4. 如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。
  5. 如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。
  6. 如果 Bean 实现了 BeanPostProcessor 接口,则 Spring 调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作。
  7. 如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。
  8. 如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。
  9. 如果 Bean 实现了 BeanPostProcessor 接口,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization(),此处非常重要,Spring 的 AOP 就是利用它实现的。
  10. 此时,Bean 已经可以被应用系统使用了。
  11. 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法销毁 Bean。
  12. 如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。

3、常用接口方法说明

对于上面的接口和方法,可以分为以下三大类:

  • Bean自身的方法:比如构造函数、getter/setter 以及 Bean 中自定义的初始化方法(init-method)和销毁方法(destory-method)等;
  • Bean直接实现的接口的方法:比如BeanNameAwareBeanFactoryAwareInitializingBeanDisposableBean等方法,这些方法只对当前 Bean 生效;
  • 容器级生命周期的方法:这些接口的实现类是独立于 Bean 的,并且会注册到 Spring 容器中,在 Spring 容器创建任何 Bean 的时候,这些接口对应的方法都会发生作用。比如InstantiationAwareBeanPostProcessorBeanPostProcessor接口里的方法。

    Bean自身的方法Bean直接实现的接口的方法只对当前Bean起作用,但是容器级生命周期方法是对所有的bean都起作用的。

3.1 Bean自身的方法

Bean 的构造方法和 getter/setter 方法就不在介绍了,主要介绍一下通过@Bean(initMethod="initMethod", destroyMethod="destroyMethod")注解实现的初始化和销毁方法。

3.1.1 @Bean(initMethod=”initMethod”, destroyMethod=”destroyMethod”)

Spring 支持用户在 Bean 中自定义 Bean 的初始化和销毁时做的动作,即用户在 Bean 类中声明 public 的初始化和销毁方法,在公共的 BeanConfig 里通过@Bean注解创建这个 Bean 时,在@Bean注解里通过initMethoddestroyMethod参数将 Bean 类中自定义的初始化方法名和销毁方法名传入。

需要注意的是:

  • @Bean注解里initMethod参数指定的初始化 Bean 的方法,是在InitializingBean接口的afterPropertiesSet()方法执行之后再执行的;
  • @Bean注解里destroyMethod参数指定的销毁 Bean 的方法,是在DisposableBean接口的destroy()方法执行之后再实行的。

@Bean(initMethod="initMethod", destroyMethod="destroyMethod")的Demo如下:

  1. @Configuration
  2. @ComponentScans(value= {@ComponentScan("com.jerry.springbootstudy.lifecycle")})
  3. public class LifeCycleConfig {
  4. @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
  5. public User user()
  6. {
  7. return new User();
  8. }
  9. }
  10. @Component
  11. public class User implements {
  12. public void initMethod() {
  13. System.out.println("调用自定义的init方法初始化方法");
  14. }
  15. public void destroyMethod() {
  16. System.out.println("调用自定义的destroy方法销毁对象");
  17. }
  18. }

3.2 Bean直接实现的接口的方法

这三个接口在平时开发中基本都没用过。

3.2.1 BeanNameAware接口

BeanNameAware接口是个函数式接口,只有一个方法void setBeanName(String s),通过该接口可以获取 Bean 的 name,demo 如下:

  1. @Service
  2. public class BizService implements BeanNameAware {
  3. private String beanName;
  4. @Override
  5. public void setBeanName(String s) {
  6. this.beanName = s;
  7. }
  8. public String getBeanName() {
  9. return beanName;
  10. }
  11. }

BizService 实例可以通过调用getBeanName()方法获取当前 BizService 实例(Bean)的 beanName。

3.2.2 BeanFactoryAware接口

BeanFactoryAware接口也是一个函数式接口,只有一个方法void setBeanFactory(BeanFactory beanFactory) throws BeansException,通过该接口可以获取当前 Bean 对应的 beanFactory 的引用,demo 如下:

  1. @Service
  2. public class BizService implements BeanFactoryAware {
  3. private BeanFactory factory;
  4. @Override
  5. public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
  6. this.factory = beanFactory;
  7. }
  8. public BeanFactory getFactory() {
  9. return factory;
  10. }
  11. }

BizService 实例可以通过调用getFactory()方法获取当前 BizService 实例(Bean)对应的 beanFactory 的引用。

这里简要介绍一下 Spring 的 BeanFactory :Spring 提供了两种类型的IOC容器:BeanFactory 接口和 ApplicationContext 接口,二者的关系是 BeanFactory 接口是 ApplicationContext 接口的父父接口;
二者的区别在于:

  • BeanFactory 是基础类型的Ioc容器,默认采取延迟初始化(懒加载)策略,所谓懒加载是指在容器初始化时并没有初始化容器中的bean,只有当程序需要访问其中一个被容器管理的对象时才会对bean进行初始化及其注入操作;
  • ApplicationContext 在 BeanFactory 基础上构建,除了拥有 BeanFactory 的所有特性,它还支持事件发布、国际化信息的支持等。另外,ApplicationContext 管理的对象会在容器初始化的时候将其全部初始化。

    3.2.3 ApplicationContextAware接口

    ApplicationContextAware接口也是一个函数式接口,只有一个方法:void setApplicationContext(ApplicationContext applicationContext)throws BeansException,通过该接口可以获取 Spring 的上下文ApplicationContext 实例。Demo 如下: ```java

public class ApplicationContextUtil implements ApplicationContextAware{

  1. private static ApplicationContext applicationContext;
  2. /**
  3. * 实现ApplicationContextAware接口的回调方法,设置上下文环境
  4. *
  5. * @param applicationContext spring上下文对象
  6. * @throws BeansException 抛出spring异常
  7. */
  8. @Override
  9. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  10. ApplicationContextUtil.applicationContext = applicationContext;
  11. }
  12. /**
  13. * @return ApplicationContext
  14. */
  15. public static ApplicationContext getApplicationContext() {
  16. return applicationContext;
  17. }
  18. /**
  19. * 获取对象
  20. *
  21. * @param name spring配置文件中配置的bean名或注解的名称
  22. * @return 一个以所给名字注册的bean的实例
  23. * @throws BeansException 抛出spring异常
  24. */
  25. @SuppressWarnings("unchecked")
  26. public static <T> T getBean(String name) throws BeansException {
  27. return (T) applicationContext.getBean(name);
  28. }
  29. /**
  30. * 获取类型为requiredType的对象
  31. *
  32. * @param clazz 需要获取的bean的类型
  33. * @return 该类型的一个在ioc容器中的bean
  34. * @throws BeansException 抛出spring异常
  35. */
  36. public static <T> T getBean(Class<T> clazz) throws BeansException {
  37. return applicationContext.getBean(clazz);
  38. }
  39. /**
  40. * 如果ioc容器中包含一个与所给名称匹配的bean定义,则返回true否则返回false
  41. *
  42. * @param name ioc容器中注册的bean名称
  43. * @return 存在返回true否则返回false
  44. */
  45. public static boolean containsBean(String name) {
  46. return applicationContext.containsBean(name);
  47. }

}

  1. 获取到了 Spring 的上下文,意味着你可以通过实现类的实例获取 Spring 中的所有 Bean,或者判断当前上下文中是否含有指定名称的 Bean,但貌似实际项目中也没用到过。
  2. <a name="z8YGz"></a>
  3. ### 3.2.4 InitializingBean接口
  4. `InitializingBean`接口也是一个函数式接口,只有一个方法:`void afterPropertiesSet() throws Exception`,通过该接口可以自定义 Bean 初始化时执行的操作。使用场景比如某功能需要在 Spring 启动(对应的就是你这个服务启动)的时候就执行,而不是通过自动注入 Bean 然后调用 Bean 的方法去触发,这个时候就可以将执行操作写在`afterPropertiesSet`方法里,IOC容器选择 ApplicationContext ,在 Spring 容器初始化的时候就初始化 Bean ,进而调用`afterPropertiesSet`方法里要执行的操作。<br />`InitializingBean`接口的简单demo如下:
  5. ```java
  6. @Service
  7. public class TestInitializingBean implements InitializingBean{
  8. private Logger logger = LoggerFactory.getLogger(TestInitializingBean.class);
  9. @Override
  10. public void afterPropertiesSet() throws Exception {
  11. logger.info("开始工作......");
  12. logger.info("结束工作......");
  13. }
  14. }

这里说一下3.1.1中@Bean(initMethod="initMethod", destroyMethod="destroyMethod")中指定的初始化方法和InitializingBean接口的afterPropertiesSet方法的异同点:

  • 相同点:功能都是 Bean 初始化时指定要执行的操作;
  • 不同点:
    • @Bean注解中的init-method参数是通过反射执行的,而afterPropertiesSet是直接执行的,因此afterPropertiesSet的效率要高一些;
    • 执行顺序上**afterPropertiesSet**先执行,**@Bean**注解中的**init-method**后执行

      3.2.5 DisposableBean接口

      DisposableBean接口也是一个函数式接口,只有一个方法void destroy(),在容器销毁的时候调用,且DisposableBean接口定义的destroy方法先执行,@Bean(initMethod="initMethod", destroyMethod="destroyMethod")中指定的销毁方法后执行。

3.3 容器级生命周期方法

3.3.1 BeanPostProcessor接口

该接口也叫后置处理器,作用是在 Bean 对象在实例化和依赖注入完毕后,在显示调用初始化方法InitializingBean接口的afterPropertiesSet方法或自定义的init方法)的前后添加我们自己的逻辑。接口中有两个方法,如下:

  1. public interface BeanPostProcessor {
  2. //实例化、依赖注入完毕,在调用显式的初始化之前完成一些定制的初始化任务。
  3. Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
  4. //实例化、依赖注入、初始化完毕时执行定制的任务。
  5. Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
  6. }

postProcessBeforeInitializationInitializingBean接口的afterPropertiesSet方法或自定义的init-method方法执行前调用,postProcessAfterInitializationInitializingBean接口的afterPropertiesSet方法或自定义的init-method方法执行后调用。

3.3.2 InstantiationAwareBeanPostProcessor接口

InstantiationAwareBeanPostProcessor接口是BeanPostProcessor的子接口,该接口跟 Bean 的实例化过程有关,接口中有3个方法(不包含父接口BeanPostProcessor里的2个方法),如下:

  1. package org.springframework.beans.factory.config;
  2. public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
  3. Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
  4. boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
  5. PropertyValues postProcessPropertyValues(
  6. PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;
  7. }
postProcessBeforeInstantiation 该方法在目标对象实例化之前调用,该方法的返回值类型是Object。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法返回为null,后续的方法都正常执行,如果该方法返回实例对象,则后续方法都不执行,直接执行BeanPostProcessor接口的postProcessAfterInitialization方法。
postProcessAfterInstantiation 在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是 null。该方法的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素(因为还有一个因素是mbd.getDependencyCheck()),如果该方法返回 false,并且不需要 check,那么postProcessPropertyValues就会被忽略不执行;如果返回 true,postProcessProperties方法就会被执行。
postProcessProperties 如果postProcessAfterInstantiation方法返回 false,该方法可能不会被调用。此时属性值还未被设置,但是可以通过postProcessProperties方法修改原本应该设置进去的属性值。

注意区分两个单词:

单词 含义 对应接口
Instantiation 表示实例化,对象还未生成 InstantiationAwareBeanPostProcessor接口
Initialization 表示初始化,对象已经生成 BeanPostProcessor接口

3.3.3 BeanFactoryPostProcessor接口

BeanFactoryPostProcessor接口也是一个函数式接口,只有一个方法postProcessBeanFactory,如下:

  1. public interface BeanFactoryPostProcessor {
  2. void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
  3. }

实现该接口,可以对beanDifinition进行修改。也就是说,Spring 允许BeanFactoryPostProcessor在容器实例化任何 Bean 之前读取配置元数据(beanDifinition),并可以根据需要进行修改,例如可以把 Bean 的 scope 从 singleton 改为 prototype,也可以把 property 的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置 order 属性来控制各个BeanFactoryPostProcessor的执行次序。注意:**BeanFactoryPostProcessor****postProcessBeanFactory**方法的执行顺序在**InstantiationAwareBeanPostProcessor**接口的**postProcessBeforeInstantiation**方法执行之前。

4、Spring生命周期Demo

根据第一节介绍的 Spring 生命周期详细的过程,设计 Demo 验证整个流程。
User:

  1. @Component
  2. public class User implements InitializingBean, BeanNameAware, DisposableBean {
  3. @Value("001")
  4. private String id;
  5. @Value("Jerry")
  6. private String name;
  7. public User() {
  8. System.out.println("3、调用构造函数");
  9. }
  10. public void initMethod() {
  11. System.out.println("9、调用自定义的init方法初始化方法");
  12. }
  13. public void destroyMethod() {
  14. System.out.println("12、调用自定义的destroy方法销毁对象");
  15. }
  16. public String getId() {
  17. return id;
  18. }
  19. public void setId(String id) {
  20. this.id = id;
  21. System.out.println("5、属性注入(id)");
  22. }
  23. public String getName() {
  24. return name;
  25. }
  26. public void setName(String name) {
  27. this.name = name;
  28. System.out.println("5、属性注入(name)");
  29. }
  30. @Override
  31. public void afterPropertiesSet() throws Exception {
  32. System.out.println("8、调用InitializingBean实例的afterPropertiesSet");
  33. }
  34. @Override
  35. public void setBeanName(String name) {
  36. System.out.println("6、调用BeanNameAware接口的setBeanName方法");
  37. }
  38. @Override
  39. public void destroy() throws Exception {
  40. System.out.println("11、调用DisposableBean接口的destroy方法");
  41. }
  42. }

User类中主要定义了 Bean 自身的方法和 Bean 实现的接口。

MyBeanFactoryPostProcessor:

  1. public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
  2. @Override
  3. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  4. System.out.println("1、调用BeanFactoryPostProcessor接口的postProcessBeanFactory方法,beanFactory: " + beanFactory);
  5. }
  6. }

MyBeanPostProcessor:

  1. public class MyBeanPostProcessor implements BeanPostProcessor {
  2. @Override
  3. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  4. System.out.println("7、调用BeanPostProcessor接口的postProcessBeforeInitialization方法, bean:" + beanName);
  5. return bean;
  6. }
  7. @Override
  8. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  9. User user = (User) bean;
  10. System.out.println("10、调用BeanPostProcessor接口的postProcessAfterInitialization方法, user id is: " + user.getId() + ", user name is: " + user.getName());
  11. return bean;
  12. }
  13. }

MyInstantiationAwareBeanPostProcessor:

  1. public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
  2. @Override
  3. public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
  4. System.out.println("2、调用InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation方法");
  5. return null;
  6. }
  7. @Override
  8. public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
  9. System.out.println("4、调用InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation方法");
  10. return true;
  11. }
  12. @Override
  13. public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
  14. System.out.println("5、调用InstantiationAwareBeanPostProcessor接口的postProcessProperties方法");
  15. return pvs;
  16. }
  17. }

MyBeanFactoryPostProcessorMyBeanPostProcessorMyInstantiationAwareBeanPostProcessor是 Spring 容器级方法对应的接口的实现类。

LifeCycleConfig:

  1. @Configuration
  2. @ComponentScans(value= {@ComponentScan("com.jerry.springbootstudy.lifecycle")})
  3. public class LifeCycleConfig {
  4. @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
  5. public User user()
  6. {
  7. return new User();
  8. }
  9. @Bean
  10. public MyBeanPostProcessor myBeanPostProcessor() {
  11. return new MyBeanPostProcessor();
  12. }
  13. @Bean
  14. public MyBeanFactoryPostProcessor myBeanFactoryPostProcessor() {
  15. return new MyBeanFactoryPostProcessor();
  16. }
  17. @Bean
  18. public MyInstantiationAwareBeanPostProcessor myInstantiationAwareBeanPostProcessor() {
  19. return new MyInstantiationAwareBeanPostProcessor();
  20. }
  21. }

配置类,网上很多例子都是基于 Spring xml 配置文件的,但是现在开发项目中应该基本没有再用xml配置文件的了,都是用的 Config 类导入,这里 LifeCycleConfig 相当于一个主配置类(BeanConfig)。

LifeCycleConfigTest:

  1. public class LifeCycleConfigTest {
  2. public static void main(String[] args) {
  3. // 基于配置类创建容器
  4. AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
  5. // 从容器中获取bean
  6. Object user = ctx.getBean("user");
  7. // 销毁容器
  8. ctx.close();
  9. }
  10. }

注意这里要写成 main 函数启动的方式,而不是之前那种 Spirng 程序的启动方式,测试代码中通过AnnotationConfigApplicationContext生成 Spring 基于注解的上下文,再从上下文中获取 Bean,完成 user Bean 的初始化,并通过打印消息的方式代表对应的初始化方法已经执行了。为了打印结果对齐,没有采用log打印日志,而是通过System.out.println的方式将日志打印到控制台,启动 Spring 应用后,控制台的打印结果如下:
image.png

参考文档

  1. 书籍参考
  2. Spring 通过三级缓存解决循环依赖原理分析
  3. Spring Bean 的生命周期
  4. SpringBoot 生命周期