天天看點

spring 單例的循環依賴

現象

  • 兩個類都是spring的單例類,兩個類裡面有一個成員變量,變量都是對方。
@Component
public class BeanA
{
	@Resource
	private BeanB beanB;
	
}

@Component
class BeanB
{
	@Resource
	private BeanA beanA;
	
}
           

這個問題不是什麼複雜的問題。正常思路是這樣的。

BeanA a = new BeanA();
BeanB b = new BeanB();

a.setBeanB(b);
b.setBeanA(a);
           

spring 建立對象

spring的思路是這樣子的,這個就出現了循環依賴的問題

public static BeanA createA() {

	BeanA beanA = new BeanA();
	BeanB b = createB();
	beanA.setBeanB(b);
	return beanA;
}

public static BeanB createB() {
	BeanB beanB = new BeanB();
	BeanA a = createA();
	beanB.setBeanA(a);
	return beanB;
}
           

spring的理念是,隻要你建立一個對象,那麼這個對象中的需要自動注入的屬性就要即時注入,如果沒有就建立這個屬性,或者報錯。

  • spring的解決方式(引入緩存)僞代碼
private static Map<String,Object> cacheObjects = new HashMap<>();

	public static BeanA createA() {
		// 先從緩存中擷取
		BeanA beanA = (BeanA) cacheObjects.get("beanA");
		if (beanA != null){
			return beanA;
		}
		beanA = new BeanA();
		cacheObjects.put("beanA",beanA);
		BeanB b = createB();
		beanA.setBeanB(b);
		return beanA;
	}

	public static BeanB createB() {
		// 先從緩存中擷取
		BeanB beanB = (BeanB) cacheObjects.get("beanB");
		if (beanB != null){
			return beanB;
		}
		beanB = new BeanB();
		cacheObjects.put("beanB",beanB);
		BeanA a = createA();
		beanB.setBeanA(a);
		return beanB;
	}
           

源碼解讀

流程圖

spring 單例的循環依賴
  • 先嘗試從緩存中拿取執行個體
// 從緩存中拿取執行個體
		Object sharedInstance = getSingleton(beanName);
           

緩存容器

/** Cache of singleton factories: bean name to ObjectFactory. */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
           

從緩存中先嘗試擷取

....
	Object singletonObject = null;
		// 從三級緩存中擷取執行個體
	ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
	if (singletonFactory != null) {
		singletonObject = singletonFactory.getObject();
	}

	return singletonObject;
		....
           

如果對象不存在建立一個對象

// 建立執行個體
	instanceWrapper = createBeanInstance(beanName, mbd, args);
           

建立對象之後加入緩存,注意這個對象是一個空的對象。

之後來進行屬性注入

// 擷取有@AutoWired 注解的字段和方法
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			// 進行設定值
			metadata.inject(bean, beanName, pvs);
		}
           
// 擷取依賴注入的值
	value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
           

如果它是一個對象類型的資料,最終觸發getBean操作

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
		throws BeansException {

	return beanFactory.getBean(beanName);
}