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. } 
  23. }); 
  24. bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 
  25. } 
  26. // 省略...... 
  27. } 

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. } 
  21. } 
  22. } 
  23. } 
  24. return (singletonObject != NULL_OBJECT ? singletonObject : null); 
  25. } 
  26. /** 
  27. * Return the (raw) singleton object registered under the given name, 
  28. * creating and registering a new one if none registered yet. 
  29. * @param beanName the name of the bean 
  30. * @param singletonFactory the ObjectFactory to lazily create the singleton 
  31. * with, if necessary 
  32. * @return the registered singleton object 
  33. */ 
  34. public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { 
  35. synchronized (this.singletonObjects) { 
  36. Object singletonObject = this.singletonObjects.get(beanName); 
  37. if (singletonObject == null) { 
  38. // 省略...... 
  39. try { 
  40. singletonObject = singletonFactory.getObject(); 
  41. newSingleton = true; 
  42. } 
  43. catch (IllegalStateException ex) { 
  44. // 省略...... 
  45. } 
  46. catch (BeanCreationException ex) { 
  47. // 省略......; 
  48. } 
  49. finally { 
  50. // 省略...... 
  51. afterSingletonCreation(beanName); 
  52. } 
  53. if (newSingleton) { 
  54. addSingleton(beanName, singletonObject); 
  55. } 
  56. } 
  57. return (singletonObject != NULL_OBJECT ? singletonObject : null); 
  58. } 
  59. } 

这里先从从缓存中拿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. } 
  21. if (instanceWrapper == null) { 
  22. instanceWrapper = createBeanInstance(beanName, mbd, args); 
  23. } 
  24. final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); 
  25. Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); 
  26. mbd.resolvedTargetType = beanType; 
  27. // 省略...... 
  28. // Eagerly cache singletons to be able to resolve circular references 
  29. // even when triggered by lifecycle interfaces like BeanFactoryAware. 
  30. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); 
  31. if (earlySingletonExposure) { 
  32. // 省略...... 
  33. addSingletonFactory(beanName, new ObjectFactory<Object>() { 
  34. @Override 
  35. public Object getObject() throws BeansException { 
  36. return getEarlyBeanReference(beanName, mbd, bean); 
  37. } 
  38. }); 
  39. } 
  40. // Initialize the bean instance. 
  41. Object exposedObject = bean; 
  42. try { 
  43. populateBean(beanName, mbd, instanceWrapper); 
  44. if (exposedObject != null) { 
  45. exposedObject = initializeBean(beanName, exposedObject, mbd); 
  46. } 
  47. } catch (Throwable ex) { 
  48. // 省略...... 
  49. } 
  50. // 省略...... 
  51. // Register bean as disposable. 
  52. try { 
  53. registerDisposableBeanIfNecessary(beanName, bean, mbd); 
  54. } catch (BeanDefinitionValidationException ex) { 
  55. // 省略...... 
  56. } 
  57. return exposedObject; 
  58. } 

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. } 
  21. } 
  22. } 
  23. } 
  24. return (singletonObject != NULL_OBJECT ? singletonObject : null); 
  25. } 

从代码中可以看出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. } 
  7. if (instanceWrapper == null) { 
  8. instanceWrapper = createBeanInstance(beanName, mbd, args); 
  9. } 
  10. final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); 
  11. Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); 
  12. // 省略...... 
  13. // Eagerly cache singletons to be able to resolve circular references 
  14. // even when triggered by lifecycle interfaces like BeanFactoryAware. 
  15. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); 
  16. if (earlySingletonExposure) { 
  17. if (logger.isDebugEnabled()) { 
  18. // 省略...... 
  19. } 
  20. addSingletonFactory(beanName, new ObjectFactory<Object>() { 
  21. @Override 
  22. public Object getObject() throws BeansException { 
  23. return getEarlyBeanReference(beanName, mbd, bean); 
  24. } 
  25. }); 
  26. } 
  27. } 
  28.  
  29. /** 
  30. * Add the given singleton factory for building the specified singleton if necessary. 
  31. * <p>To be called for eager registration of singletons, e.g. to be able to 
  32. * resolve circular references. 
  33. * @param beanName the name of the bean 
  34. * @param singletonFactory the factory for the singleton object 
  35. */ 
  36. protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { 
  37. Assert.notNull(singletonFactory, "Singleton factory must not be null"); 
  38. synchronized (this.singletonObjects) { 
  39. if (!this.singletonObjects.containsKey(beanName)) { 
  40. this.singletonFactories.put(beanName, singletonFactory); 
  41. this.earlySingletonObjects.remove(beanName); 
  42. this.registeredSingletons.add(beanName); 
  43. } 
  44. } 
  45. } 

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

4. References

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

posted @ 2018-01-12 10:23  默默的看雨下  阅读(502)  评论(0)    收藏  举报