Spring源码学习笔记(八、Spring启动流程解析:注册后处理器、bean的生命周期)

目录:

  • 注册后处理器源码:registerBeanPostProcessors
  • BeanPostProcessor与InstantiationAwareBeanPostProcessor
  • bean的类型
  • bean的生命周期
  • spring如何解决循环依赖

注册后处理器源码:registerBeanPostProcessors

1 protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
2     PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
3 }

registerBeanPostProcessors的源码和上一节讲到的BeanFactory后置处理器非常相似,我觉得这里就没有必要再做赘述了,你可以自行翻阅。

BeanPostProcessor与InstantiationAwareBeanPostProcessor

1、BeanPostProcessor

注册后处理器中主要的重点就是BeanPostProcessor,它也是Spring容器中非常重要的一个接口,主要用于定制bean初始化前后的一些处理逻辑。

其接口定义如下:

1 // bean初始化之前的处理
2 Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
3 
4 // bean初始化之后的处理
5 Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

并且它也可以通过order属性来实现顺序调用

———————————————————————————————————————————————————————

2、InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor与BeanPostProcessor类似,也是对定制bean的接口,不同的是它不仅能够在bean初始化前后做处理,还能在bean实例化前后做处理,其定义如下。

 1 public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
 2 
 3     // bean实例化前的处理
 4     Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
 5 
 6     // bean实例化后的处理
 7     boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
 8 
 9     // 对bean属性值的处理
10     PropertyValues postProcessPropertyValues(
11             PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;
12 
13 }

由此可见bean的生命周期大致如下:

  1. 实例化前的处理
  2. 实例化
  3. 实例化后的处理
  4. 属性赋值
  5. 初始化前的处理
  6. 初始化之后的处理
  7. 销毁

bean的类型

bean的类型有两种:

  • 普通bean
  • 工厂bean(FactoryBean)

普通bean没什么好说的,就是直接用xml配置的那些bean。

而FactoryBean则是在你用xml配置难度较大,或是拥有复杂的初始化逻辑时才会去使用,其定义如下。

 1 public interface FactoryBean<T> {
 2 
 3     // 获取这个工厂创建的对象实例
 4     T getObject() throws Exception;
 5 
 6     // 获取这个bean的类型,若类型未知返回null
 7     Class<?> getObjectType();
 8 
 9     // 此bean是否为单例的bean,true=单例,false=非单例
10     boolean isSingleton();
11 }

注意:

  • 通过这种方式生成的bean,它本质还是一个Bean,但这个Bean不是用来注入到其它地方像Service、Dao一样使用的,而是用来生成其它Bean使用的。
  • Spring框架中的许多地方都使用了FactoryBean概念和接口,Spring附带了50多个FactoryBean接口实现。很多开源项目在集成Spring 时也都使用到FactoryBean,比如 MyBatis3 提供 mybatis-spring项目中的 org.mybatis.spring.SqlSessionFactoryBean

———————————————————————————————————————————————————————

示例:

1 <bean id="person" class="com.jdr.spring.PersonFactoryBean">
2     <property name="jsonInfo"
3               value="{ &quot;id&quot;: 1,&quot;name&quot;: &quot;abc&quot;,
4                      &quot;age&quot;: 27, &quot;salary&quot;: 5555.0,
5                      &quot;address&quot;: &quot;beijing&quot;}"/>
6 </bean>
 1 public class PersonFactoryBean implements FactoryBean<Person> {
 2 
 3     private String jsonInfo;
 4 
 5     @Override
 6     public Person getObject() throws Exception {
 7         ObjectMapper om = new ObjectMapper();
 8         return om.readValue(jsonInfo, Person.class);
 9     }
10 
11     @Override
12     public Class<?> getObjectType() {
13         return Person.class;
14     }
15 
16     @Override
17     public boolean isSingleton() {
18         return false;
19     }
20 
21     public String getJsonInfo() {
22         return jsonInfo;
23     }
24 
25     public void setJsonInfo(String jsonInfo) {
26         this.jsonInfo = jsonInfo;
27     }
28 }

bean的生命周期

Spring Bean的生命周期只有四个阶段:

  • 实例化(Instantiation):调用构造函数
  • 属性赋值(Populate):设置依赖注入
  • 初始化(Initialization):调用init方法
  • 销毁(Destruction):调用destory方法

生命周期也可以理解为四个等级。每个等级中都用有相应的接口,实现其中某个接口或者将实现类注入到Spring容器,容器就会在相应的时机调用其方法。

  • 工厂级处理器接口
  • 容器级生命周期接口
  • Bean级生命周期接口
  • Bean本身方法

生命周期接口详述:

  • BeanFactoryPostProcessor:工厂后处理器接口;容器创建完毕,装配Bean源后立即调用。
  • InstantiationAwareBeanPostProcessor:容器后处理器接口;分别在调用构造之前,注入属性之前,实例化完成时调用。
  • BeanPostProcessor:容器后处理器接口;分别在Bean的初始化方法调用前后执行。
  • BeanNameAware:Bean级后置处理器接口;注入属性后调用。
  • BeanFactoryAware:Bean级后置处理器接口;注入属性后调用。
  • InitializingBean:Bean级后置处理器接口;在类本身的初始化方法之前调用其方法(本身也是初始化方法)。
  • DisposableBean:Bean级后置处理器接口;在类本身的销毁方法执行之前调用其方法(本身也是销毁方法)。
  • init方法:Bean本身方法;在注入属性之后调用初始化方法。
  • destroy方法:Bean本身方法;在关闭容器的时候进行销毁。

Spring中Bean初始化/销毁的三种方法:

  • 通过实现InitializingBean/DisposableBean接口来定制初始化之后/销毁之前的操作方法。
  • 在<bean> 元素上添加init-method/destroy-method来指定初始化之后 /销毁之前调用的操作方法。
  • 在方法上加上@PostConstruct@PreDestroy注解来指定该方法是在初始化之后还是销毁之前调用。

Spring Bean的生命周期:

  • Spring对Bean进行实例化,调用Bean的构造参数。
  • 设置对象属性,调用Bean的set方法,将属性注入到bean的属性中。
  • 检查Bean是否实现BeanNameAware、BeanFactoryAware、ApplicationContextAware接口,如果实现了这几个接口Spring会分别调用其中实现的方法。
  • 如果Bean是否实现BeanPostProcessor接口,Spring会在初始化方法的前后分别调用postProcessBeforeInitialization和postProcessAfterInitialization方法。
  • 如果Bean是否实现InitalizingBean接口,将调用afterPropertiesSet()方法。
  • 如果Bean声明初始化方法,也会被调用。
  • 使用Bean。Bean将会一直保留在应用的上下文中,直到该应用上下文被销毁。
  • 检查Bean是否实现DisposableBean接口,Spring会调用它们的destory方法。
  • 如果Bean声明销毁方法,该方法也会被调用。

spring如何解决循环依赖

在将Spring如何解决循环依赖之前我们先了解一下什么是循环依赖。

循环依赖就是两个bean互相引用对方,也就是A引用B,B引用A,代码示例如下:

 1 public class BeanA {
 2 
 3     private BeanB beanb;
 4 
 5     // getter and setter
 6     
 7     public BeanB getBeanb() {
 8         return beanb;
 9     }
10 
11     public void setBeanb(BeanB beanb) {
12         this.beanb = beanb;
13     }
14 }
 1 public class BeanB {
 2 
 3     private BeanA beana;
 4 
 5     // getter and setter
 6 
 7     public BeanA getBeana() {
 8         return beana;
 9     }
10 
11     public void setBeana(BeanA beana) {
12         this.beana = beana;
13     }
14 }

———————————————————————————————————————————————————————

通过查阅源码你可以发现,Spring实例化一个bean的流程如下:

其中最为关键的代码如下:

 1 // 注册名称返回单例对象,检查已经实例化的单例,并允许提前引用当前创建的单例对象(解析循环引用)
 2 protected Object getSingleton(String beanName, boolean allowEarlyReference) {
 3     // 从单例缓存中根据Bean名字获取单例对象
 4     Object singletonObject = this.singletonObjects.get(beanName);
 5     // 如果单例对象为空,并且单例对象正在创建中
 6     if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
 7         // 注意synchronized关键字
 8         synchronized (this.singletonObjects) {
 9             // 从earlySingletonObjects缓存中通过Bean名称获取对象
10             singletonObject = this.earlySingletonObjects.get(beanName);
11             // 如果单例对象仍然为空,并且允许提前引用为true
12             // allowEarlyReference参数含义:是否允许提前曝光
13             if (singletonObject == null && allowEarlyReference) {
14                 // 从singletonFactories中根据Bean名称获取对应的单例工厂
15                 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
16                 if (singletonFactory != null) {
17                     // 通过工厂创建单例对象(此时还未进行依赖注入)
18                     singletonObject = singletonFactory.getObject();
19                     // 把创建的单例对象放到提前引用的缓存
20                     this.earlySingletonObjects.put(beanName, singletonObject);
21                     // 移除该单例对象的工厂
22                     this.singletonFactories.remove(beanName);
23                 }
24             }
25         }
26     }
27 }

由整体流程了解下来,解决循环依赖最关键的就是这四个缓存:

  • singletonObjects:初始化完成的单例对象缓存。
  • earlySingletonObjects:提前曝光的单例对象缓存。
  • singletonFactories:单例Bean的工厂函数对象缓存。
  • singletonsCurrentlyInCreation:即将创建的单例集合。

你可以通过这张图配合着理解:

当A在试图填充B的时候,发现B还未实例化,所以就先去创建B;但创建B的时候又发现A还实例化中,所以又去实例化A。

此时A又会取重新走流程,并从三级缓存singletonFactories拿到A后再去实例化B,这个实例化其实只是提前曝光;此后B已经实例化完毕。

最后再转到A,A来填充B,以上,完成实例化。

posted @ 2020-06-01 16:29  被猪附身的人  阅读(224)  评论(0编辑  收藏  举报