zoukankan      html  css  js  c++  java
  • 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,以上,完成实例化。

  • 相关阅读:
    Leetcode 70 Climbing Stairs 递推
    Leetcode 83 Remove Duplicates from Sorted List 链表
    Leetcode 328 Odd Even Linked List 链表
    Leetcode 206 Reverse Linked List 链表
    Spring中注解
    SpringMVC配置文件
    java设计模式----单例模式
    java设计模式----工厂方法模式
    java设计模式----装饰者模式
    java设计模式----观察者模式
  • 原文地址:https://www.cnblogs.com/bzfsdr/p/12995614.html
Copyright © 2011-2022 走看看