天天看點

Spring解決循環依賴問題

作者:奮鬥的架構師

先看為什麼循環依賴怎麼出現的? 比如有AService和BService,具體代碼如下:

class AService {
    @Autowired
    BService b;
}
class BService {
    @Autowired
    AService a;
}           

上面的代碼 A中引入了B,B中引入了A,這樣當spring執行個體A的時候,看到@Autowired引入了BService,然後會去執行個體化BService,執行個體化BService的時候,屬性中又引入了AService,是以又會去執行個體化AService,如此循環下去産生了循環依賴。

解決方法

在執行個體化A後(屬性注入之前),把它放入一個Map中暫時叫Map1,然後再注入屬性,執行個體化B去,執行個體化B的時候,B又需要引入A,此時直接從前面的Map1中去取出,
此時取出的A和前面執行個體化的A是同一個引用。
然後B執行個體化完并且屬性注入完成後,繼續執行A的屬性注入流程,後續A屬性注入也完成了。因為A都是同一個引用,是以此時B中持有的是完整的A執行個體。
A執行個體化完整後,再把A放入另一個Map中,這個Map都是放完整的執行個體化後的類的,上面的Map1存放的是沒有注入屬性的執行個體化類。           

看樣子不需要三級緩存了為什麼還需要三級緩存?

三級緩存主要為了解決動态代理的問題。

下圖總結的圖檔

Spring解決循環依賴問題

源碼細節

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
		...
		// 從三級緩存中擷取執行個體對象的邏輯,注意這裡可能來自于一級緩存/二級緩存/三級緩存
		Object sharedInstance = getSingleton(beanName);
		// 如果緩存中有,就進行一定的邏輯處理直接傳回。
		if (sharedInstance != null && args == null) {
			// 傳回執行個體對象。
			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
		else {
	        // 調用建立執行個體的方法
			if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
		}
}

	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		// 從一級緩存讀取執行個體對象(完整的執行個體對象)
		Object singletonObject = this.singletonObjects.get(beanName);
		// 如果一級緩存沒有
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		    // 從二級緩存擷取執行個體對象
			singletonObject = this.earlySingletonObjects.get(beanName);
			// 如果二級緩存沒有
			if (singletonObject == null && allowEarlyReference) {
			    // 加一個鎖,保證一緻性,待研究
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
					singletonObject = this.singletonObjects.get(beanName);
					// 一級緩存沒有,從二級緩存拿
					if (singletonObject == null) {
						singletonObject = this.earlySingletonObjects.get(beanName);
						// 二級緩存沒有,從三級緩存拿
						if (singletonObject == null) {
						    // 從三級緩存拿,拿出來的是一個FactoryBean
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
							    // 調用FactoryBean的getObject方法。這裡可能會生成代理對象,也可能是非代理對象
								singletonObject = singletonFactory.getObject();
								// 生成的對象,放入二級緩存
								this.earlySingletonObjects.put(beanName, singletonObject);
								// 删除三級緩存的類
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}           

上面重要的方法是createBean,它調用了doCreateBean,它是重要的方法繼續分析

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   // Eagerly cache singletons to be able to resolve circular references
   // even when triggered by lifecycle interfaces like BeanFactoryAware.
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
         isSingletonCurrentlyInCreation(beanName));
   if (earlySingletonExposure) {
      if (logger.isTraceEnabled()) {
         logger.trace("Eagerly caching bean '" + beanName +
               "' to allow for resolving potential circular references");
      }
      // 重要的方法,注意第二個參數是lamda表達式,看他傳入的參數是ObjectFactory,隻有一個方法getObject
           // 就是在上面getSingleton方法中會去調用觸發的。addSingletonFactory會把ObjectFactory對象
           // 放入三級緩存中。
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }
   ...
   Object exposedObject = bean;
   try {
       // 屬性注入,在這個方法中會再次執行doGetBean方法,第二次再此執行該方法的時候,緩存中就會存在第一次進入的時候執行個體化好的半成品bean了。
      populateBean(beanName, mbd, instanceWrapper);
      // 調用各種回調接口
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   }           

繼續分析getEarlyBeanReference

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
      Object exposedObject = bean;
      if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            // 周遊實作了SmartInstantiationAwareBeanPostProcessor接口的實作類
         for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
                // 這裡是擷取FactoryBean執行個體的
            exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
      return exposedObject;
   }
/**
 * 此方法是核心,預設的實作是直接傳回傳入的bean執行個體
 */
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        return bean;
}           

這裡還有一個SmartInstantiationAwareBeanPostProcessor的實作類,就是生産AOP代理類AbstractAutoProxyCreator,看它的getEarlyBeanReference方法

@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      this.earlyProxyReferences.put(cacheKey, bean);
      return wrapIfNecessary(bean, beanName, cacheKey);
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        ...
        // Create proxy if we have advice.
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            // 生成動态代理,這塊在我的另一個文檔中分析動态代理生成的地方有提到。
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }
        ...
}