当前位置:   article > 正文

深入理解Spring Bean的生命周期(通俗易懂/图文详解)

深入理解Spring Bean的生命周期(通俗易懂/图文详解)

目录

一、前言

二、突破点

三、生命周期

1、bean的定义

2、bean的自定义扩展 

3、Spring容器接管

四、代码验证

1、定义bean信息文件applicationContext.xml

2、创建userInfoBean

3、创建InstantiationAwareBeanPostProcessor 接口实现类

4、创建BeanPostProcessor 接口实现类

5、创建BeanFactoryPostProcessor 接口实现类

6、测试类

7、运行结果


一、前言

网上谈这个问题的很多,但基本都是按照源码的执行顺序,时间久了很容易忘记。
换个思路,spring作为一个非常优秀的框架,从设计者的角度去考虑,bean的生命周期是怎么被设计出来的?或者说是怎么被完善的?反而更容易理解!

有时候看了很多博文,可能也被以下问题弄的一头雾水:

  1. 很多博文开篇就先贴一张流程图,这个流程图的起点是如何确定的?
  2. 有些博文,上来就是源码,那么源码阅读的思路是什么?
  3. 当自己想解决这个问题时,应该通过怎样的方式?
  4. 如何来验证我们理解的正确性?

我们从先找突破点。

二、突破点

任何一门技术,最权威的解释还是对应的官方,所以第一步应该是从官网入手。

打开官网,我们先找下官方对Spring容器以及bean的相关介绍:

图中标注部分,简而言之就是以下两个意思:

1、org.springframework.beans和org.springframework.context是非常关键的两个包;
2、ApplicationContext 继承了BeanFactory(可以感觉到,这两个对象应该比较关键);

既然官网这么说,我们就从BeanFactory 和 ApplicationContext 入手:

先看下BeanFactory源码中的注释,尤其是第一句:

  1. /**
  2. * The root interface for accessing a Spring bean container.
  3. *
  4. * ...省略...
  5. *
  6. *
  7. * <p>Bean factory implementations should support the standard bean lifecycle interfaces
  8. * as far as possible. The full set of initialization methods and their standard order is:
  9. * <ol>
  10. * <li>BeanNameAware's {@code setBeanName}
  11. * <li>BeanClassLoaderAware's {@code setBeanClassLoader}
  12. * <li>BeanFactoryAware's {@code setBeanFactory}
  13. * <li>EnvironmentAware's {@code setEnvironment}
  14. * <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
  15. * <li>ResourceLoaderAware's {@code setResourceLoader}
  16. * (only applicable when running in an application context)
  17. * <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
  18. * (only applicable when running in an application context)
  19. * <li>MessageSourceAware's {@code setMessageSource}
  20. * (only applicable when running in an application context)
  21. * <li>ApplicationContextAware's {@code setApplicationContext}
  22. * (only applicable when running in an application context)
  23. * <li>ServletContextAware's {@code setServletContext}
  24. * (only applicable when running in a web application context)
  25. * <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
  26. * <li>InitializingBean's {@code afterPropertiesSet}
  27. * <li>a custom init-method definition
  28. * <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
  29. * </ol>
  30. *
  31. * <p>On shutdown of a bean factory, the following lifecycle methods apply:
  32. * <ol>
  33. * <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
  34. * <li>DisposableBean's {@code destroy}
  35. * <li>a custom destroy-method definition
  36. * </ol>
  37. *
  38. * ...省略...
  39. *
  40. */
  41. public interface BeanFactory {...}

注释中第一句: 

源码注释:

The root interface for accessing a Spring bean container.

字面翻译:

访问SpringBean容器的根接口

为什么SpringBean被称为根接口,它做了什么?

继续看BeanFactory源码:

源码注释:

Bean factory implementations should support the standard bean lifecycle interfaces
 * as far as possible. The full set of initialization methods and their standard order is:

... ...

翻译过来还是两点:

1、定义了一个标准的bean的生命周期

2、规范了bean在整个生命周期中,各个方法的执行顺序。

从这里看出,BeanFactory应该是起点,那么ApplicationContext又有什么不同?

官方给出了明确的回复,简单理解:

BeanFactory是发展大纲,定义了发展方向;

ApplicationContext 是执行守则,定义了执行方向。

通过分析ApplicationContext的继承关系,确实也继承了BeanFactory,所以分析bean的生命周期自然通过BeanFactory入手。

三、生命周期

通常我们会在这里先提供一个完整的流程图来展示整个流程,这种思维方式是按照阅读源码的方式,逻辑清晰,但是时间长了容易忘记。

按照官网文档的描述,我们可以换个方式,从bean的自身方法、生命周期、容器管理三个层级来思考,然后逐层补充扩展来看下。

1、bean的定义

 这是官方提供的对bean的定义,可以归为四类:构造方法、属性、初始化(init-method)、bean销毁(destory-method)。

结合源码,我们可以梳理出bean自身的生命周期:

2、bean的自定义扩展 

The Spring Framework provides a number of interfaces you can use to customize the nature of a bean. This section groups them as follows:

  • Lifecycle Callbacks
  • ApplicationContextAware and BeanNameAware
  • Other Aware Interfaces

在官网可以到,spring对bean提供了很多扩展接口,这些接口也贯穿bean的生命周期,这些接口也会和spring容器进行交互,保持bean自身及在spring容器整个过程中生命周期的一致性。

Aware接口在开篇BeanFactory源码注释中已经说明了调用顺序,所以,bean的生命周期流程图又拓展为:

继续跟官方文档:

Lifecycle Callbacks
To interact with the container’s management of the bean lifecycle, you can implement the Spring InitializingBean and DisposableBean interfaces. The container calls afterPropertiesSet() for the former and destroy() for the latter to let the bean perform certain actions upon initialization and destruction of your beans. 

新增了bean初始化方法和容器销毁的方法

为避免引起歧义,原来的“初始化”节点,加上了“init-method”标注。

3、Spring容器接管

到这里,bean自身以及拓展的阶段以及完成,bean开始由spring容器进行管理。 

容器主要通过BeanPostProcessor进行管理bean,BeanPostProcessor被称为后置处理器:

  1. public interface BeanPostProcessor {
  2. Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
  3. Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
  4. }

postProcessBeforeInitialization方法会在每一个bean对象的初始化方法调用之前回调;

postProcessAfterInitialization方法会在每个bean对象的初始化方法调用之后被回调。

于是,流程图继续完善:

原本到这里,按照BeanFactory中的方法调用,可以结束了,但是在阅读 BeanPostProcessor源码时,提到了InstantiationAwareBeanPostProcessor

/**
 * @author Juergen Hoeller
 * @author Sam Brannen
 * @since 10.10.2003
 * @see InstantiationAwareBeanPostProcessor
 * @see DestructionAwareBeanPostProcessor
 * @see ConfigurableBeanFactory#addBeanPostProcessor
 * @see BeanFactoryPostProcessor
 */
public interface BeanPostProcessor {...}

InstantiationAwareBeanPostProcessor是BeanFactory的子类,用法和BeanFactory类似.

  1. /**
  2.  * Subinterface of {@link BeanPostProcessor} that adds a before-instantiation callback,
  3.  * and a callback after instantiation but before explicit properties are set or
  4.  * autowiring occurs.
  5.  * ...
  6.  */
  7. public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
  8. //在bean实例化之前调用
  9. postProcessBeforeInstantiation(Class beanClass, String beanName){...}
  10. //在bean实例化之后、设置属性前调用
  11. postProcessProperties(PropertyValues pvs, Object bean, String beanName){...}
  12. //在bean实例化之后调用
  13. postProcessAfterInstantiation(Class beanClass, String beanName){..}
  14. }

通过注释内容可以了解,该类在bean初始化前和初始化后调用,于是流程图继续完善:

四、代码验证

1、定义bean信息文件applicationContext.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans
  6. https://www.springframework.org/schema/beans/spring-beans.xsd
  7. ">
  8. <bean class="com.zhufeng.bean.MyInstantiationAwareBeanPostProcessor" />
  9. <bean id="userInfoBean" class="com.zhufeng.bean.UserInfoBean" init-method="init" destroy-method="destroyMethod">
  10. <!-- setter方法注入 -->
  11. <property name="userId" value="user1001"/>
  12. <property name="name" value="月夜烛峰"/>
  13. </bean>
  14. <bean class="com.zhufeng.bean.MyBeanPostProcessor" />
  15. <bean class="com.zhufeng.bean.MyBeanFactoryPostProcessor" />
  16. </beans>

2、创建userInfoBean

  1. package com.zhufeng.bean;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.BeanNameAware;
  4. import org.springframework.beans.factory.DisposableBean;
  5. import org.springframework.beans.factory.InitializingBean;
  6. import org.springframework.context.ApplicationContext;
  7. import org.springframework.context.ApplicationContextAware;
  8. /**
  9. * @ClassName: UserInfoBean
  10. * @Description 创建userInfoBean
  11. * @author 月夜烛峰
  12. * @date 2022/9/6 22:18
  13. */
  14. public class UserInfoBean implements InitializingBean, BeanNameAware, DisposableBean, ApplicationContextAware {
  15. private String userId;
  16. private String name;
  17. public UserInfoBean (){
  18. System.out.println("2. 调用构造方法");
  19. }
  20. public String getUserId() {
  21. return userId;
  22. }
  23. public void setUserId(String userId) {
  24. this.userId = userId;
  25. System.out.println("5. 属性注入 userId");
  26. }
  27. public String getName() {
  28. return name;
  29. }
  30. public void setName(String name) {
  31. this.name = name;
  32. System.out.println("5. 属性注入 name");
  33. }
  34. @Override
  35. public String toString() {
  36. return "UserInfoBean{userId='" + userId +"', name='" + name + "'}";
  37. }
  38. @Override
  39. public void setBeanName(String name) {
  40. System.out.println("6. 调用 BeanNameAware#setBeanName() 方法");
  41. }
  42. @Override
  43. public void destroy() throws Exception {
  44. System.out.println("12. 调用 DisposableBean#destroy() 方法");
  45. }
  46. public void init() {
  47. System.out.println("10. 调用 init-method 方法");
  48. }
  49. public void destroyMethod() {
  50. System.out.println("13. 调用 destroy-method 方法");
  51. }
  52. @Override
  53. public void afterPropertiesSet() throws Exception {
  54. System.out.println("9. 调用 InitializingBean#afterPropertiesSet() 方法");
  55. }
  56. @Override
  57. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  58. System.out.println("7. 获取 ApplicationContext 上下文信息");
  59. UserInfoBean userBean = (UserInfoBean) applicationContext.getBean("userInfoBean");
  60. System.out.println(userBean);
  61. }
  62. }

3、创建InstantiationAwareBeanPostProcessor 接口实现类

  1. package com.zhufeng.bean;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.PropertyValues;
  4. import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
  5. /**
  6. * @ClassName: MyInstantiationAwareBeanPostProcessor
  7. * @Description TODO
  8. * @author 月夜烛峰
  9. * @date 2022/9/6 22:32
  10. */
  11. public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
  12. @Override
  13. public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
  14. if ("userInfoBean".equals(beanName)) {
  15. System.out.println("1. 调用 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation() 方法");
  16. }
  17. return null;
  18. }
  19. @Override
  20. public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
  21. if ("userInfoBean".equals(beanName)) {
  22. UserInfoBean userInfoBean = (UserInfoBean) bean;
  23. System.out.println("3. 调用 InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation() 方法");
  24. System.out.println(userInfoBean);
  25. }
  26. return true;
  27. }
  28. @Override
  29. public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
  30. if ("userInfoBean".equals(beanName)) {
  31. System.out.println("4. 调用 InstantiationAwareBeanPostProcessor#postProcessProperties() 方法");
  32. }
  33. return null;
  34. }
  35. }

4、创建BeanPostProcessor 接口实现类

  1. package com.zhufeng.bean;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.config.BeanPostProcessor;
  4. /**
  5. * @ClassName: MyBeanPostProcessor
  6. * @Description TODO
  7. * @author 月夜烛峰
  8. * @date 2022/9/6 22:31
  9. */
  10. public class MyBeanPostProcessor implements BeanPostProcessor {
  11. @Override
  12. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  13. if ("userInfoBean".equals(beanName)) {
  14. System.out.println("8. 调用 BeanPostProcessor#postProcessBeforeInitialization() 方法");
  15. }
  16. return bean;
  17. }
  18. @Override
  19. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  20. if ("userInfoBean".equals(beanName)) {
  21. System.out.println("11. 调用 BeanPostProcessor#postProcessAfterInitialization() 方法");
  22. }
  23. return bean;
  24. }
  25. }

5、创建BeanFactoryPostProcessor 接口实现类

  1. package com.zhufeng.bean;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
  4. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  5. /**
  6. * @ClassName: MyBeanFactoryPostProcessor
  7. * @Description TODO
  8. * @author 月夜烛峰
  9. * @date 2022/9/6 22:32
  10. */
  11. public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
  12. @Override
  13. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  14. System.out.println("0. 调用 BeanFactoryPostProcessor#postProcessBeanFactory() 方法");
  15. }
  16. }

6、测试类

  1. package com.zhufeng.bean;
  2. import ch.qos.logback.classic.Level;
  3. import org.junit.After;
  4. import org.junit.Before;
  5. import org.junit.Test;
  6. import org.springframework.context.ApplicationContext;
  7. import org.springframework.context.support.ClassPathXmlApplicationContext;
  8. /**
  9. * @ClassName: BeanLifeCycleManager
  10. * @Description 代码模拟bean生命周期
  11. * @author 月夜烛峰
  12. * @date 2022/9/6 22:37
  13. */
  14. public class BeanLifeCycleManager {
  15. @Before
  16. public void before() {
  17. ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) org.slf4j.LoggerFactory
  18. .getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
  19. root.setLevel(Level.INFO);
  20. System.out.println("---bean生命周期开始---");
  21. }
  22. @After
  23. public void after() {
  24. System.out.println("---bean生命周期结束---");
  25. }
  26. @Test
  27. public void testBean(){
  28. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  29. context.getBean("userInfoBean");
  30. //触发销毁方法
  31. ((ClassPathXmlApplicationContext) context).close();
  32. }
  33. }

7、运行结果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/编程变革者/article/detail/62617
推荐阅读
相关标签
  

闽ICP备14008679号