Ref: https://mp.weixin.qq.com/s/zb6eA3Se0gQoqL8PylCPLw

简单说说 IoC 和 Bean

IoC,控制反转,想必大家都知道,所谓的控制反转,就是把 new 对象的权利交给容器,所有的对象都被容器控制,这就叫所谓的控制反转。
Bean 生命周期 - 图1
控制反转
Bean,也不是什么新鲜玩意儿,它们就是一帮身不由己的 Java 对象,生命周期受到容器控制。

Bean 生命周期

Bean 生命周期四大阶段

我们知道,bean 的作用域有好几种,这篇文章只讨论完全被 IoC 容器控制的单例 Bean。
对于普通的 Java 对象来说,它们的生命周期就是:

  • 实例化
  • 对象不再被使用时通过垃圾回收机制进行回收

而对于 Spring Bean 的生命周期来说,可以分为四个阶段,其中初始化完成之后,就代表这个Bean可以使用了:

  • 实例化 Instantiation
  • 属性赋值 Populate
  • 初始化 Initialization
  • 销毁 Destruction

Bean 生命周期 - 图2
Bean 实例化的时机也分为两种:

  • BeanFactory 管理的 Bean 是在使用到 Bean 的时候才会实例化 Bean
  • ApplicantContext 管理的 Bean 在容器初始化的时候就会完成 Bean 实例化

BeanFactory 就是相对不那么健全的原始一些的社会,ApplicantContext 是发达健全的现代社会。
BeanFactory 和 Applicantcontext

Bean 详细生命周期

Bean 容器四个阶段,会有一些容器级的方法,进行前置和后置的处理,比如InstantiationAwareBeanPostProcessor、BeanPostProcessor 接口方法。这些方法独立于Bean之外,并且会注册到 Spring 容器中,在 Spring 容器创建 Bean 的时候,进行一些处理。
后处理器
有了各种各样的扩展之后,接着看看Bean的详细的生命周期。首先,我们面临一个问题——Bean的生命周期从什么时候开始的呢?
上面写了,Bean实例化前后,可以进行一些处理,但是如果从Bean实例化前算开始,那么就要追溯到容器的初始化、beanDefiinition的加载开始。
所以这里取生命周期直接从 Bean 实例化开始,但是大家也要知道,Bean实例化前后,可以使用后处理器进行处理,例如 BeanFactoryPostProcessor、InstantiationAwareBeanPostProcessor。
大家也不要困扰,就像计算人生的起点,是从母亲怀孕算起,还是从孩子出生算起?我们这里取了出生开始而已。
Bean 生命周期 - 图5
Bean生命周期

  • 实例化:第 1 步,实例化一个 Bean 对象
  • 属性赋值:第 2 步,为 Bean 设置相关属性和依赖
  • 初始化:初始化的阶段的步骤比较多,5、6步是真正的初始化,第 3、4 步为在初始化前执行,第 7 步在初始化后执行,初始化完成之后,Bean就可以被使用了
  • 销毁:第 8~10步,第8步其实也可以算到销毁阶段,但不是真正意义上的销毁,而是先在使用前注册了销毁的相关调用接口,为了后面第9、10步真正销毁 Bean 时再执行相应的方法

中间的一些扩展过程也可以分四类:
Bean 生命周期 - 图6

  1. 获取社会资源 / Aware接口:Aware 接口的作用是让 Bean 能拿到容器的一些资源,例如BeanNameAware可以拿到BeanName。就好像上学之前,要取一个学名——不知道多少人上学之前不知道自己大名叫什么,是吧?二毛。
  2. 必备各种手续和证 / 后处理器:在 Bean 的生命周期里,会有一些后处理器,它们的作用就是进行一些前置和后置的处理,就像上学之前,需要登记学籍,上学之后,会拿到毕业证。
  3. 个人选择 / 生命周期接口:人可能无法选择如何出生,但也许可以选择如何活着和如何死去,InitializingBean和DisposableBean 接口就是用来定义初始化方法和销毁方法的。
  4. 主观能动 / 配置生命周期方法:环境影响人,人也在影响环境,成长的时候认真努力,衰亡的时候也可以豁达乐观。可以通过配置文件,自定义初始化(init-method)和销毁(destory-method)方法。

    PersonBean 的一生

    看看PersonBean的一生,我们先来看一下它的流程!
    PersonBean的一生
    用文字描述一下这个过程:

  5. Bean 容器在配置文件中找到 PersonBean 的定义,这个可以说是妈妈怀上了。

  6. Bean 容器使用 Java 反射 API 创建 Bean 的实例,孩子出生了。
  7. Person 声明了属性 no、name,它们会被设置,相当于注册身份证号和姓名。如果属性本身是 Bean,则将对其进行解析和设置。
  8. Person 类实现了 BeanNameAware 接口,通过传递 Bean 的名称来调用 setBeanName() 方法,相当于起个学名。
  9. Person 类实现了 BeanFactoryAware 接口,通过传递 BeanFactory 对象的实例来调用 setBeanFactory() 方法,就像是选了一个学校。
  10. PersonBean 实现了 BeanPostProcessor 接口,在初始化之前调用用 postProcessBeforeInitialization() 方法,相当于入学报名。
  11. PersonBean 类实现了 InitializingBean 接口,在设置了配置文件中定义的所有 Bean 属性后,调用afterPropertiesSet()方法,就像是入学登记。
  12. 配置文件中的Bean定义包含init-method属性,该属性的值将解析为Person类中的方法名称,初始化的时候会调用这个方法,成长不是走个流程,还需要自己不断努力。
  13. Bean Factory对象如果附加了Bean 后置处理器,就会调用postProcessAfterInitialization()方法,毕业了,总得拿个证。
  14. Person类实现了DisposableBean接口,则当Application不再需要Bean引用时,将调用destroy()方法,简单说,就是人挂了。
  15. 配置文件中的Person Bean定义包含destroy-method属性,所以会调用Person类中的相应方法定义,相当于选好地儿,埋了。

    PersonBean 类

    创建一个 PersonBean,让它实现几个特殊的接口,我们来观察一下它的生命周期的流转。 ```java public class PersonBean implements InitializingBean, BeanFactoryAware, BeanNameAware, DisposableBean {

    /**

    • 身份证号 */ private Integer no;

      /**

    • 姓名 */ private String name;

      public PersonBean() { System.out.println(“1.调用构造方法:我出生了!”); }

      public Integer getNo() { return no; }

      public void setNo(Integer no) { this.no = no; }

      public String getName() { return name; }

      public void setName(String name) { this.name = name; System.out.println(“2.设置属性:我的名字叫”+name); }

      @Override public void setBeanName(String s) { System.out.println(“3.调用BeanNameAware#setBeanName方法:我要上学了,起了个学名”); }

      @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println(“4.调用BeanFactoryAware#setBeanFactory方法:选好学校了”); }

      @Override public void afterPropertiesSet() throws Exception { System.out.println(“6.InitializingBean#afterPropertiesSet方法:入学登记”); }

      public void init() { System.out.println(“7.自定义init方法:努力上学ing”); }

      @Override public void destroy() throws Exception { System.out.println(“9.DisposableBean#destroy方法:平淡的一生落幕了”); }

      public void destroyMethod() { System.out.println(“10.自定义destroy方法:睡了,别想叫醒我”); }

      public void work(){ System.out.println(“Bean使用中:工作,只有对社会没有用的人才放假。。”); }

}

  1. - 实现了 InitializingBean, BeanFactoryAware, BeanNameAware, DisposableBean 四个接口
  2. - 定义了 noname 两个属性和对应的 gettersetter 方法
  3. - 定义了一个实例方法 work
  4. <a name="w1vvK"></a>
  5. ## MyBeanPostProcessor
  6. 自定义了一个后处理器 MyBeanPostProcessor
  7. ```java
  8. public class MyBeanPostProcessor implements BeanPostProcessor {
  9. @Override
  10. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  11. System.out.println("5.BeanPostProcessor.postProcessBeforeInitialization方法:到学校报名啦");
  12. return bean;
  13. }
  14. @Override
  15. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  16. System.out.println("8.BeanPostProcessor#postProcessAfterInitialization方法:终于毕业,拿到毕业证啦!");
  17. return bean;
  18. }
  19. }

配置文件

定义一个配置文件spring-config.xml:

  • 使用 setter 注入
  • 定义 init-method 和 destroy-method ```xml <?xml version=”1.0” encoding=”UTF-8”?>

<a name="IVQUu"></a>
## 测试
最后测试一下,观察 PersonBean 的生命周期的流转:
```java
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        PersonBean personBean = (PersonBean) context.getBean("personBean");
        personBean.work();
        ((ClassPathXmlApplicationContext) context).destroy();
    }
}

运行结果:

1.调用构造方法:我出生了!
2.设置属性:我的名字叫张铁钢
3.调用BeanNameAware#setBeanName方法:我要上学了,起了个学名
4.调用BeanFactoryAware#setBeanFactory方法:选好学校了
5.BeanPostProcessor#postProcessBeforeInitialization方法:到学校报名啦
6.InitializingBean#afterPropertiesSet方法:入学登记
7.自定义init方法:努力上学ing
8.BeanPostProcessor#postProcessAfterInitialization方法:终于毕业,拿到毕业证啦!
Bean使用中:工作,只有对社会没有用的人才放假。。
9.DisposableBean#destroy方法:平淡的一生落幕了
10.自定义destroy方法:睡了,别想叫醒我

看看,是不是和我们图中的流程一致。
这篇文章就不带大家跟进更多的源码了,如果大家对源码级别的 Bean 的生命周期感兴趣,可以看看AbstractApplicationContext 类里的 refresh 方法,这个方法是 AplicationContext 容器初始化的关键点。在这个方法里,调用了 finishBeanFactoryInitialization 方法,这个方法里调用了 getBean 方法,getBean 方法里调用了 AbstractBeanFactory 的 getBean 方法。
Bean生命周期源码追踪
最终经过一阵七拐八绕,到达了我们的目标——Bean 创建的方法:doGetBean 方法,在这个方法里可以看到Bean的实例化,赋值、初始化的过程,至于最终的销毁,可以看看 ConfigurableApplicationContext#close().

结语

到这,这篇Bean的生命周期文章就走向destory了,自定义destory方法——回顾一下这篇文章的“一生”。

  • Bean的生命周期大致可以分为四个阶段:实例化、属性赋值、初始化、销毁,对应人生的出生、登记、成长、离世。
  • Bean生命周期中可以有很多扩展,就像人生的走向,会受很多影响,社会的环境、自身的选择、自己的努力。