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的生命周期大致如下:
- 实例化前的处理
- 实例化
- 实例化后的处理
- 属性赋值
- 初始化前的处理
- 初始化之后的处理
- 销毁
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="{ "id": 1,"name": "abc", 4 "age": 27, "salary": 5555.0, 5 "address": "beijing"}"/> 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,以上,完成实例化。