• Spring IOC 循环依赖


    Spring IOC 循环依赖

    1. 概述


    Spring循环依赖是使用Spring过程中容易遇到的问题,这篇文章主要讲Spring如何处理循环依赖问题。这里主要讲的是Spring解决一般单例对象的循环依赖问题。注入方式如下:

    1. <bean class="com.kanyuxia.spring.bean.constructandsetter.Dog" name="dog" lazy-init="true"> 
    2. <property name="pig" ref="pig" /> 
    3. </bean> 

    2. Spring IOC对Bean的初始化


    由于涉及到Spring对于一般单例对象的循环依赖问题,所以先简单看一下Spring对单例对象的初始化过程。这里主要讲了大概的初始化过程,对于特殊情况,如ProxyBean、FactoryBean等没有进行详细的说明。
    2.1 大概流程如下

    • 从Resource(如XML)中读取Bean的定义并把其初始化为BeanDefinition对象。这里,当Bean的lazy-init属性为true时,不进行Bean的初始化
    • 当调用Spring容器的AbstractBeanFactory.getBean(beanName)方法时,Spring正式开始初始化Bean。首先通过DefaultSingletonBeanRegistry.getSingleton()方法从缓存获取Bean,例如lazy-init为false时Bean对象已经创建并放入缓存中,或者当解决循环依赖时也是在缓存中读取
    • 如果从缓存中没有获取Bean则需要创建Bean,通过调用AbstractAutoWireCapableBeanFactory.createBean()方法创建Bean
    • 调用AbstractAutoWireCapableBeanFactory.createBeanInstance()方法实例化Bean。
    • 调用DefaultSingletonBeanRegistry.addSingletonFactory()方法添加一个SingletonFactory缓存,这里是Spring解决循环依赖的关键点
    • 调用AbstractAutoWireCapableBeanFactory.populateBean()方法为Bean填充属性。
    • 调用AbstractAutoWireCapableBeanFactory.initializeBean()方法来初始化Bean,调用Bean时的init()方法、工厂回调、Bean Post处理器等等

    2.2 流程图如下 (画的不好,见谅)
    enter description here

    2.3 相关代码如下

    AbstractBeanFactory的doGetBean()方法

    1. protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException
    2. final String beanName = transformedBeanName(name); 
    3. Object bean; 
    4. // Eagerly check singleton cache for manually registered singletons. 
    5. Object sharedInstance = getSingleton(beanName); 
    6. if (sharedInstance != null && args == null) { 
    7. // 省略..... 
    8. bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); 
    9. } else
    10. // 省略...... 
    11. // Create bean instance. 
    12. if (mbd.isSingleton()) { 
    13. sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { 
    14. @Override 
    15. public Object getObject() throws BeansException
    16. try
    17. return createBean(beanName, mbd, args); 
    18. } catch (BeansException ex) { 
    19. destroySingleton(beanName); 
    20. throw ex; 


    21. }); 
    22. bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 

    23. // 省略...... 

    DefaultSingletonBeanRegistry的两个getSingleton()方法,一个从缓存中读取Bean,另一个通过调用ObjectFactory创建Bean

    1. /** 
    2. * Return the (raw) singleton object registered under the given name. 
    3. * <p>Checks already instantiated singletons and also allows for an early 
    4. * reference to a currently created singleton (resolving a circular reference). 
    5. * @param beanName the name of the bean to look for 
    6. * @param allowEarlyReference whether early references should be created or not 
    7. * @return the registered singleton object, or {@code null} if none found 
    8. */ 
    9. protected Object getSingleton(String beanName, boolean allowEarlyReference)
    10. Object singletonObject = this.singletonObjects.get(beanName); 
    11. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { 
    12. synchronized (this.singletonObjects) { 
    13. singletonObject = this.earlySingletonObjects.get(beanName); 
    14. if (singletonObject == null && allowEarlyReference) { 
    15. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); 
    16. if (singletonFactory != null) { 
    17. singletonObject = singletonFactory.getObject(); 
    18. this.earlySingletonObjects.put(beanName, singletonObject); 
    19. this.singletonFactories.remove(beanName); 




    20. return (singletonObject != NULL_OBJECT ? singletonObject : null); 

    21. /** 
    22. * Return the (raw) singleton object registered under the given name, 
    23. * creating and registering a new one if none registered yet. 
    24. * @param beanName the name of the bean 
    25. * @param singletonFactory the ObjectFactory to lazily create the singleton 
    26. * with, if necessary 
    27. * @return the registered singleton object 
    28. */ 
    29. public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory)
    30. synchronized (this.singletonObjects) { 
    31. Object singletonObject = this.singletonObjects.get(beanName); 
    32. if (singletonObject == null) { 
    33. // 省略...... 
    34. try
    35. singletonObject = singletonFactory.getObject(); 
    36. newSingleton = true

    37. catch (IllegalStateException ex) { 
    38. // 省略...... 

    39. catch (BeanCreationException ex) { 
    40. // 省略......; 

    41. finally
    42. // 省略...... 
    43. afterSingletonCreation(beanName); 

    44. if (newSingleton) { 
    45. addSingleton(beanName, singletonObject); 


    46. return (singletonObject != NULL_OBJECT ? singletonObject : null); 


    这里先从从缓存中拿Bean(这里解决的依赖注入问题),没有则通过创建一个匿名ObjectFactory对象来创建对象。

    然后就是createBean(),下面是AbstractAutowireCapableBeanFactory.doCreateBean()方法

    1. /** 
    2. * Actually create the specified bean. Pre-creation processing has already happened 
    3. * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks. 
    4. * <p>Differentiates between default bean instantiation, use of a 
    5. * factory method, and autowiring a constructor. 
    6. * @param beanName the name of the bean 
    7. * @param mbd the merged bean definition for the bean 
    8. * @param args explicit arguments to use for constructor or factory method invocation 
    9. * @return a new instance of the bean 
    10. * @throws BeanCreationException if the bean could not be created 
    11. * @see #instantiateBean 
    12. * @see #instantiateUsingFactoryMethod 
    13. * @see #autowireConstructor 
    14. */ 
    15. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException
    16. // Instantiate the bean. 
    17. BeanWrapper instanceWrapper = null
    18. if (mbd.isSingleton()) { 
    19. instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); 

    20. if (instanceWrapper == null) { 
    21. instanceWrapper = createBeanInstance(beanName, mbd, args); 

    22. final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); 
    23. Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); 
    24. mbd.resolvedTargetType = beanType; 
    25. // 省略...... 
    26. // Eagerly cache singletons to be able to resolve circular references 
    27. // even when triggered by lifecycle interfaces like BeanFactoryAware. 
    28. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); 
    29. if (earlySingletonExposure) { 
    30. // 省略...... 
    31. addSingletonFactory(beanName, new ObjectFactory<Object>() { 
    32. @Override 
    33. public Object getObject() throws BeansException
    34. return getEarlyBeanReference(beanName, mbd, bean); 

    35. }); 

    36. // Initialize the bean instance. 
    37. Object exposedObject = bean; 
    38. try
    39. populateBean(beanName, mbd, instanceWrapper); 
    40. if (exposedObject != null) { 
    41. exposedObject = initializeBean(beanName, exposedObject, mbd); 

    42. } catch (Throwable ex) { 
    43. // 省略...... 

    44. // 省略...... 
    45. // Register bean as disposable. 
    46. try
    47. registerDisposableBeanIfNecessary(beanName, bean, mbd); 
    48. } catch (BeanDefinitionValidationException ex) { 
    49. // 省略...... 

    50. return exposedObject; 

    3. Spring IOC对Bean循环依赖的解决方案


    3.1 循环依赖
    循环依赖指的是多个对象之间相互依赖,例如A对象依赖B对象,B对象依赖A对象,这样就形成了一个环。Java中循环依赖主要有以下几种情况:

    1. A的构造方法依赖B对象,同时B对象的构造方法依赖于A
    2. A的构造方法依赖B对象,同时B对象的Field依赖于A
    3. A的Filed依赖B对象,同时B对象的构造方法依赖于A
    4. A的Filed依赖B对象,同时B对象的Filed依赖于A

    3.3 Spring的解决方案
    从前面看的出来,Spring对Singleton对象的初始化有四步:

    1. 从缓存中取Bean
    2. createBeanInstance,实例化Bean对象,就是通过构造方法构造Bean对象。当构造完成后会缓存一个singletonFactory,这里解决的依赖注入问题
    3. populateBean,填充对象属性,这里会对Bean的属性进行注入
    4. initialzeBean,实例化Bean,这里主要是注入Bean的特殊属性

    所以从上面我们可以看出Spring可以解决第3、第4种情况下的依赖注入,对于第1、第2种则没有办法解决,会抛出BeanCurrentlyInCreationException异常。

    下面是主要代码逻辑:

    首先从缓存中去取Bean

    //  Cache of singleton objects: bean name --> bean instance
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
    
    // Cache of singleton factories: bean name --> ObjectFactory
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
    
    // Cache of early singleton objects: bean name --> bean instance
    private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
    

    这里主要涉及到以上三种Spring对Singleton Bean的缓存

    1. /** 
    2. * Return the (raw) singleton object registered under the given name. 
    3. * <p>Checks already instantiated singletons and also allows for an early 
    4. * reference to a currently created singleton (resolving a circular reference). 
    5. * @param beanName the name of the bean to look for 
    6. * @param allowEarlyReference whether early references should be created or not 
    7. * @return the registered singleton object, or {@code null} if none found 
    8. */ 
    9. protected Object getSingleton(String beanName, boolean allowEarlyReference)
    10. Object singletonObject = this.singletonObjects.get(beanName); 
    11. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { 
    12. synchronized (this.singletonObjects) { 
    13. singletonObject = this.earlySingletonObjects.get(beanName); 
    14. if (singletonObject == null && allowEarlyReference) { 
    15. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); 
    16. if (singletonFactory != null) { 
    17. singletonObject = singletonFactory.getObject(); 
    18. this.earlySingletonObjects.put(beanName, singletonObject); 
    19. this.singletonFactories.remove(beanName); 




    20. return (singletonObject != NULL_OBJECT ? singletonObject : null); 

    从代码中可以看出Spring会依次从三种缓存中去取Singleton Bean

    当Bean调用createBeanInstance()方法(构造Bean)后会调用addSingletonFactory()方法把构造的Singleton Bean通过ObjectFactory存放到singletonFactory缓存中。

    1. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException {  
    2. // Instantiate the bean. 
    3. BeanWrapper instanceWrapper = null
    4. if (mbd.isSingleton()) { 
    5. instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); 

    6. if (instanceWrapper == null) { 
    7. instanceWrapper = createBeanInstance(beanName, mbd, args); 

    8. final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); 
    9. Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); 
    10. // 省略...... 
    11. // Eagerly cache singletons to be able to resolve circular references 
    12. // even when triggered by lifecycle interfaces like BeanFactoryAware. 
    13. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); 
    14. if (earlySingletonExposure) { 
    15. if (logger.isDebugEnabled()) { 
    16. // 省略...... 

    17. addSingletonFactory(beanName, new ObjectFactory<Object>() { 
    18. @Override 
    19. public Object getObject() throws BeansException
    20. return getEarlyBeanReference(beanName, mbd, bean); 

    21. }); 


    22.  
    23. /** 
    24. * Add the given singleton factory for building the specified singleton if necessary. 
    25. * <p>To be called for eager registration of singletons, e.g. to be able to 
    26. * resolve circular references. 
    27. * @param beanName the name of the bean 
    28. * @param singletonFactory the factory for the singleton object 
    29. */ 
    30. protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
    31. Assert.notNull(singletonFactory, "Singleton factory must not be null"); 
    32. synchronized (this.singletonObjects) { 
    33. if (!this.singletonObjects.containsKey(beanName)) { 
    34. this.singletonFactories.put(beanName, singletonFactory); 
    35. this.earlySingletonObjects.remove(beanName); 
    36. this.registeredSingletons.add(beanName); 



    这里通过缓存ObjectFactory提前把Singleton Bean暴露出来了,后面在进行构造其他对象时可以直接从缓存中取,这里就解决的循环依赖问题。

    4. References

    https://www.jianshu.com/p/6c359768b1dc
    https://www.jianshu.com/p/ecc60703d315
    https://www.jianshu.com/p/d76318d09b22

  • 相关阅读:
    设计模式(15)-命令模式
    设计模式(14)-模板方法模式
    设计模式(13)-代理模式
    设计模式(12)-享元模式
    设计模式(3)-工厂方法模式
    微服务(1)-简单初始化项目
    MCMC:Markov Chain&Monte Carlo(二)MH采样和Gibbs采样,MCMC局限性
    MCMC:Markov Chain& Monte Carlo(一)基本cdf采样,rejection采样,Importance采样
    指数族分布:相关概念理解
    matlab隐马尔可夫相关函数简单例子实现(help文档)
  • 原文地址:https://www.cnblogs.com/maying3010/p/8274501.html
Copyright © 2020-2023  润新知