Spring IOC 循环依赖

ε祈祈猫儿з 提交于 2020-12-29 06:30:46

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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!