美文网首页
Bean实例化过程以及循环依赖

Bean实例化过程以及循环依赖

作者: aiwen2017 | 来源:发表于2019-04-01 20:41 被阅读0次

    1. Bean创建

    1. 实例化Bean

    对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,便实例化所有的bean。容器通过获取BeanDefinition对象中的信息进行实例化。并且这一步仅仅是简单的实例化,仅仅利用构造函数通过反射实例化出对象,并未进行依赖注入。

    2. 依赖注入

    实例化后的对象被封装在BeanWrapper对象中,并且此时对象仍然是一个原生的状态,并没有进行依赖注入。紧接着Spring根据BeanDefinition中的信息进行依赖注入。并且通过BeanWrapper提供的设置属性的接口完成依赖注入。如果此Bean的属性的类型被注册了属性编辑器则会通过属性编辑器实例化属性。

    3. Aware接口

    紧接着,Spring会检测该对象是否实现了xxxAware接口,并调用相关的xxxAware实例的方法,这里的xxxAware有:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware。

    4. BeanPostProcessor前置处理器

    接口BeanPostProcessor的方法postProcessBeforeInitialzation( Object bean, String beanName)开始执行。此方法返回bean实例,也就是说这里有机会更换实例,如果这里返回null则后面的BeanPostProcessor均不再进行下去。

    5 InitializingBean、init-method

    如果bean实现了InitializingBean接口或者指定了init-method,则afterPropertiesSet()或者指定初始化方法执行。

    6 BeanPostProcessor后置处理器

    接口BeanPostProcessor的方法postProcessAfterInitialization( Object bean, String beanName)开始执行。此方法返回bean实例,也就是说这里有机会更换实例,如果这里返回null则后面的BeanPostProcessor均不再进行下去。
    4,5,6过程实现如下:
    1,applyBeanPostProcessorsBeforeInitialization(Object bean, String beanName)
    2,invokeInitMethods(String, Object bean, RootBeanDefinition mbd)
    3,applyBeanPostProcessorsAfterInitialization(Object bean, String beanName)

    7. DisposableBean和destroy-method

    注册DisposableBean,当调用Context的close()方法时,如果bean实现了DisposableBean接口则会调用其destroy()方法,如果bean指定了destroy-method属性则会调用其指定的方法,如果二者都有则都会调用,如果destroy-method属性值为(inferred)则close()和shutdown()方法被调用。注意:这个只针对scope为singleton的bean,对于scope为prototype的bean不存在销毁的说法。

    8. FactoryBean

    如果bean实现了FactoryBean接口则会调用getObject()方法返回bean.

    2. 循环依赖

    1. A、B互相依赖且彼此均通过构造函数注入,则spring直接抛BeanCurrentlyInCreationException异常。
    2. prototype bean之间不允许循环依赖,原理:

    当创建prototype bean时会先在ThreadLocal中找此bean的name是否存在如果存在则直接异常。例如:A、B都为prototype且相互依赖,则创建流程为:

    1. 创建A对象,创建A对象前会判断是否已经创建,判断方法为在Thread Local对象中查找A名称是否存在,第一次不存在所以此时把A名称缓存至ThreadLocal。
    2. A创建的过程中发现依赖B,则开始创建B,B名称缓存至ThreadLocal。
    3. B创建的过程中发现依赖A,则开始创建A,此时发现ThreadLocal已经缓存了A则直接抛出异常。
      如下图:
      image
    2. 单例默认无参构造函数允许循环依赖,其实现原理为三级缓存:
    1. 构造函数实例化完成后缓存至singletonFactories集合,此时虽然没有完全走完实例化流程但是可以被其他bean注入。
    2. 在依赖注入阶段第一次被其他bean注入则缓存至earlySingletonObjects并移除singletonFactories缓存。
    3. 最后创建完成缓存至singletonObjects集合并移除earlySingletonObjects缓存。

    例如有这样的依赖关系:A依赖B、C,B、C依赖A。那么其创建过程如下:

    1. 请求A,在集合singletonObjects、earlySingletonObjects、singletonFactories中依次查找,发现没有。
    2. 开始创建A,先执行构造函数实例化A,把A缓存至singletonFactories中。
    3. A注入B,请求B,其过程同第1步请求A的过程。
    4. B注入A,请求A,此时A处于依赖注入阶段并且第一次在此阶段被请求,此时在集合singletonObjects、earlySingletonObjects、singletonFactories中依次查找A,发现singletonFactories中存在A(第2步放进去的),此时将A从singletonFactories中移除并且缓存至earlySingletonObjects中,然后返回给B。
    5. B注入A结束,B创建结束,A注入B结束。
    6. A注入C,C的构成过程同B。
    7. C注入A,请求A,此时在集合singletonObjects、earlySingletonObjects、singletonFactories中依次查找,当找到earlySingletonObjects时发现已经存在了(第4步中放进去的),直接将A返回给C。
    8. C注入A结束,C创建结束,A注入C结束。
    9. 从earlySingletonObjects集合中移除A并缓存至singletonObjects。至此A、B、C创建完成。

    相关文章

      网友评论

          本文标题:Bean实例化过程以及循环依赖

          本文链接:https://www.haomeiwen.com/subject/qjbbbqtx.html