bean加載之循環依賴

關於spring循環依賴說明

什麼是循環依賴

多個對象相互持有對方引用形成一個閉環。

舉例:
用一個簡單舉例,A依賴B,B依賴A情況。A–>B–>A

@Component
pubilc Class A{
    @Autowired
    private B beanB;
    
    // getter & setter
}
@Component
public Class B{
    @Autowired
    private A beanA;
    
    // getter & setter
}

spring解決循環依賴的思路

不管當前的bean有沒有循環依賴,提前實例化緩存剛實例化的bean,接着填充屬性,再緩存完成填充屬性的bean,此時的bean實例可用

爲什麼獲取bean的對象的時候會出現實例化、再填充屬性兩部分,而不是一步完成呢?

可以簡單理解爲實例化就是先在內存中佔個位子,即一個地址引用。spring在依賴注入的時候, 實際傳遞的是一個對象引用。在被依賴的時候,可以直接引用剛實例化的bean, 達到中斷了被依賴的bean對它自己屬性填充,從而避免了循環的發生。

以上述爲例:當前beanA實例化,緩存實例化的beanA, 開始填充屬性beanA,填充屬性過程中發現依賴beanB,於是開始beanB的實例化,緩存實例化後的beanB, 接着開始填充屬性beanB,填充屬性的過程中發現依賴beanA,於是在緩存中找到了剛實例化的beanA, 然後依賴注入beanA,此時注入的是beanA的引用且不可用,這樣beanB的填充屬性就完成了。beanB的填充屬性完成後,beanB實例就可用了,接着beanA完成了對beanB的依賴注入後,beanA自身的填充屬性也完成了,beanA實例也可用了。那麼此時beanB中的屬性beanA是對象引用且可用。

簡圖描述:
在這裏插入圖片描述

如圖示,在beanB依賴注入beanA時,如果沒有將剛實例化的beanA放入緩存中,那麼必然導致beanA實例化,填充屬性的時候因爲依賴beanB,又會實例化beanB,填充屬性從而無限循環下去。而開始實例化beanB,填充屬性的過程中發現依賴beanA,於是在緩存中找到了剛實例化的beanA,依賴注入beanA,此時注入的是beanA的對象引用,這樣中斷了在beanB中因爲依賴beanA,再次出現beanA的實例化、填充屬性的循環;這就是在getBean的時候爲什麼有實例化、填充屬性兩部分。

spring解決循環依賴藉助了:提前實例化、填充屬性兩步,以及緩存。理解這些,有助於分析spring源碼中對循環依賴的處理

spring能解決哪些循環依賴

spring 只解決單例setter循環依賴,對於原型模式,單例構造器注入的循環依賴沒有解決,直接拋異常,spring中沒有對原型模式的單例進行緩存,

spring解決循環依賴的思路小結中理解了spring解決循環依賴藉助了對象實例化、填充屬性兩步、緩存。那麼就很容易理解spring爲什麼不能解決構造器注入的循環依賴。構造器在實例化階段就需要持有對方引用,此時對象無法創建,也不存在。而對於原型模式的循環依賴,因爲spring不緩存原型模式下的bean實例,所以也無解。

bean加載的初步流程

在理解了上述循環依賴說明後,再理解bean加載的循環依賴,只需要對bean加載有一個全局瞭解即可,所謂全局瞭解,不需要知道bean的加載詳細的細節,關鍵是理解bean加載過程中幾個重要的流程步驟。何時初始化bean、何時緩存bean、何時實例化bean.接下來看bean如何加載的

public Object getBean(String name) throws BeansException {
	return doGetBean(name, null, null, false);
}

bean加載的邏輯

獲取bean的邏輯主要在doGetBean中完成,現在將代碼重要邏輯流程,梳理爲邏輯代碼,有個全局的思路,

注意:僞代碼,注重bean的重要流程,去掉不重要代碼,例如部分判斷,try catch,

將用戶輸入的name裝爲beanName.爲什麼要轉?name可能爲bean的別名,也可能是&開頭的名稱

(重要)從緩存中獲取單例
if(緩存中存在){
    (重要)轉爲用戶需要的最終實例,
    
}else{ 
    如果緩存中沒有,那麼正常創建流程

    if(當前bean爲原型模式且創建中) 拋異常,循環依賴
    
    當前容器沒有bean信息,存在父類容器,那麼從父類中獲取bean信息
    
    標記已經創建的bean
    
    將xml配置存儲的BeanDefinition轉爲RootBeanDefinition,如果beanName是子類,需要同時合併父類的相關屬性,爲什麼要合併轉爲RootBeanDefinition?
    
    depends-on的處理
    
    根據不同作用域創建bean實例
    if(單例){
        (重要)獲取bean
        
        
        轉爲用戶需要的最終實例,爲什麼要轉?此處獲取的bean可能是FactoryBean實例,那麼需要轉爲FactoryBean.getObject()生產實例,也可能是用戶需要的bean實例,直接返回
    }else if(原型模式){
        記錄原型模式下,當前bean爲創建中狀態
        創建bean實例
        撤銷當前bean爲創建中狀態
        
        轉爲用戶需要的最終實例
        
    }else{
        其他作用域bean的實例化,邏輯同原型模式
    }
    
}

如果有提供bean類型,則進行類型轉換

返回最終bean

bean加載的僞代碼的實現

根據加載邏輯,在看看粗糙僞代碼的獲取bean的過程

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		
	// 提取對應的beanName
	// 如果是FactoryBean,則去掉&前綴,再查看去掉&之後的name(可能爲別名)是否有對應的beanName
	final String beanName = transformedBeanName(name);
	
	// 獲取單例緩存中實例
    Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		// 返回對應的實例,已經生成了當前bean的實例,爲什麼不直接返回?
		//當前實例bean可能是一個普通的bean,也可能是一個FactoryBean的實例,
		// 如果是普通bean的實例,則直接返回,
		//如果是FactoryBean的實例並且請求的name前面有&修飾,則說明客戶端想要獲取一個工廠的實例,那麼直接返回
		//如果是FactoryBean的實例並且請求的name前面沒有&修飾,則要獲取的工廠生產的bean的實例
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	} eles {
            //只有在單例setter依賴注入情況纔會嘗試解決循環依賴,原型模式下,無解,不做處理,直接拋異常
    		if (isPrototypeCurrentlyInCreation(beanName)) {
    			throw new BeanCurrentlyInCreationException(beanName);
    		}
    
    		//如果當前容器中不存在beanName,嘗試從父容器parentBeanFactory中獲取
    		BeanFactory parentBeanFactory = getParentBeanFactory();
    		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    			   // 省略邏輯
    		}
    		
			if (!typeCheckOnly) {
				// 標記,將當前bean標記爲已創建,存放到alreadyCreated緩存池中,並且需要重新mergedBeanDefinitions
				markBeanAsCreated(beanName);
			}
			
			
		    //將xml配置存儲的BeanDefinition轉爲RootBeanDefinition,如果beanName是子類,需要同時合併父類的相關屬性
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);

			// 如果存在depends-on,則需要遞歸實例化依賴的bean
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				for (String dep : dependsOn) {
					// 緩存當前beanName的依賴
					registerDependentBean(dep, beanName);
					// 對當前bean的依賴,進行實例化
					getBean(dep);
			    }
			}
			    
			// 實例化依賴的bean後,可以實例mgd本身了
			if (mbd.isSingleton()) {
				// 創建單例bean
				sharedInstance = getSingleton(beanName, () -> {
					//創建bean
					// getSingleton(String beanName, ObjectFactory<?> singletonFactory)創建的實例,
					// 最終依賴於singletonObject = singletonFactory.getObject();,也就是依賴singletonFactory,
					// 而singletonFactory.getObject()實現是createBean,
					return createBean(beanName, mbd, args);
				});
				// sharedInstance已經完成了初始化,屬性填充
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			} else if (mbd.isPrototype()) {
				Object prototypeInstance = null;
				try {
					beforePrototypeCreation(beanName);
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			} else {
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
				}
				
				Object scopedInstance = scope.get(beanName, () -> {
					beforePrototypeCreation(beanName);
					try {
						return createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
				});
				bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
			}
	}
	
// bean的類型匹配
if (requiredType != null && !requiredType.isInstance(bean)) {
	// 代碼略
	
}

return (T) bean;
		
		
}

注意:markBeanAsCreated(beanName)中使用的alreadyCreated緩存池,在實例創建完成後,需要藉助alreadyCreated緩存池做循環依賴檢查

經過上述的流程,我想應該對bean實例化整體流程有了清晰的認識,

分析從緩存中獲取bean的實例

現在具體深入瞭解下單例模式下,如何實例化bean
首先看看從緩存中獲取實例

public Object getSingleton(String beanName) {
    // 注意,第二個參數是否允許早期依賴循環引用
	return getSingleton(beanName, true);
}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// bean創建過程中藉助了幾個單例緩存池,如:singletonObjects、singletonsCurrentlyInCreation、earlySingletonObjects、singletonFactories

	// 獲取單例緩存中實例
	// 在已經創建完成的單例bean的緩存中,獲取當前bean是否已經創建
	Object singletonObject = this.singletonObjects.get(beanName);
	// 如果當前bean實例還未創建,並且當前bean正在創建中
	// isSingletonCurrentlyInCreation(beanName)中使用邏輯,使用了singletonsCurrentlyInCreation緩存池
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			// 從正在創建中bean(此時bean已經初始化,且完成了屬性填充,但還未暴露)獲取bean實例
			singletonObject = this.earlySingletonObjects.get(beanName);
			// 如果沒有並且當前單例bean允許早起循環引用
			if (singletonObject == null && allowEarlyReference) {
				// 從單例工廠緩存中獲取創建bean的單例工廠,由單例工廠產生bean,問題:爲什麼存放單例工廠,而不直接是bean呢?
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
					//  單例工廠不爲空,則創建bean,並放入到
					singletonObject = singletonFactory.getObject();
					//此時singletonObject是一個早期剛初始化的bean,但並未填充屬性,s屬性擴展,代理等
					this.earlySingletonObjects.put(beanName, singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}

	return singletonObject;
}

實現邏輯,首先查找singletonObject單例緩存池,沒有發現,此時bean還未創建成功,接着根據條件判斷,沒有在singletonObject緩存池中獲取到實例且當前bean正在創建中,則從earlySingletonObjects緩存池中獲取(this.earlySingletonObjects.get(beanName)),發現仍然沒有, 接着從singletonFactories緩存池中查找,發現不爲空並且允許早起循環引用,於是根據當前工廠獲取bean實例,並將實例添加到earlySingletonObjects緩存池中,並從singletonFactories單例緩存池中移除

單例緩存池介紹

上述代碼中出現了幾個單例緩存池,每個單例緩存池作用,以及爲什麼需要這麼多的單例緩存池呢?
首先看看每個單例緩存池的作用

  • singletonObjects: 存放已經初始化的單例bean的實例
  • earlySingletonObjects: 存放工廠bean剛創建bean實例,此時實例還未填充屬性,代理、自定義業務邏輯等,
  • singletonFactories:存放單例bean的工廠(用於創建單例)
  • singletonsCurrentlyInCreation: 存放當前正在創建中的單例bean
  • registeredSingletons: 存放所有實例化的bean
由上述的代碼可以看出,查詢緩存池順序爲:
|----bean創建完成--|----------bean創建中--------------------|
singletonObjects-->earlySingletonObjects-->singletonFactories


根據查詢邏輯推斷,bean創建過程中存放到單例緩存池的順序依次:
|----------------創建中---------------|------創建完成-------|
singletonFactories-->earlySingletonObjects-->singletonObjects

上述單例緩存中查找單例邏輯,爲什麼這麼實現?
主要是爲了解決單例循環依賴,那麼是如何藉助這些單例緩存池解決循環依賴?
爲了回答這個問題,我們必須明白什麼時候用這些緩存池?接下里看看在哪些邏輯上使用了這些緩存池。是否如上述推斷單例bean存放到緩存池中的順序呢?

加載bean過程中是如何應用單例緩存池

回到主邏輯上,如果首次創建bean,那麼肯定沒有緩存,需要走正常創建bean的邏輯,找到單例模式下,創建bean的代碼

sharedInstance = getSingleton(beanName, () -> {
		try {
			//創建bean
			// getSingleton(String beanName, ObjectFactory<?> singletonFactory)創建的實例,
			// 最終依賴於singletonObject = singletonFactory.getObject();,也就是依賴singletonFactory,
			// 而singletonFactory.getObject()實現是createBean,
			return createBean(beanName, mbd, args);
		}
		catch (BeansException ex) {
            // 異常處理
			throw ex;
		}
	});

可以看出有兩個參數,一個是beanName,一個是匿名的ObjectFactory類,其中匿名內部類中的有個回調方法ObjectFactory.getObject(),這個方法中的createBean(beanName, mbd, args)方法似乎實現了創建bean的邏輯,此處採用Lambda 表達式,那麼getSingleton實現邏輯是什麼呢?詳細看看

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	
	synchronized (this.singletonObjects) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
			
			// 記錄beanName爲正在加載狀態 this.singletonsCurrentlyInCreation.add(beanName)
			beforeSingletonCreation(beanName);

			boolean newSingleton = false;
			
			try {
				// 獲取的可能是bean的實例,也可能是創建實例的ObjectFactory的實例
				// singletonFactory.getObject()的實現邏輯參考createBean(beanName, mbd, args)
				singletonObject = singletonFactory.getObject();
				newSingleton = true;
			} catch (Exception ex) {
			    // 省略異常處理
				throw ex;
			} finally {
				// bean創建完成後,
				// 移除beanName爲正在加載狀態 this.singletonsCurrentlyInCreation.remove(beanName)
				afterSingletonCreation(beanName);
			}
			if (newSingleton) {
				// 將實例放入singletonObjects、registeredSingletons緩存中,
				// 並刪除加載bean過程中的所記錄的輔助狀態 singletonFactories、earlySingletonObjects
				addSingleton(beanName, singletonObject);
			}
		}
		return singletonObject;
	}
}

從上面代碼可以看出getSingleton方法有兩個參數,beanName和ObjectFactory(創建bean的具體實現),
主要邏輯:

1、記錄當前bean爲正在創建狀態

將當前正在創建中的bean添加到this.singletonsCurrentlyInCreation單例緩存池

2、回調匿名內部類ObjectFactory#getObject()方法創建實例,

創建bean過程中將創建bean的工廠添加到this.singletonFactories單例緩存池、

同時將當前bean添加到this.registeredSingletons單例緩存池中,標記bean已創建

此處只需要知道這一步操作裏面有這些單例緩存池的應用場景,可以跳過閱讀下面詳細解釋。如果需要知道singletonFactories、registeredSingletons單例緩存池的詳細應用,參見下方創建bean準備工作

回調匿名內部類ObjectFactory#getObject()方法創建實例具體邏輯,此方法中涉及到singletonFactories單例緩存池、registeredSingletons單例緩存池的應用,看看是如何應用的?

創建bean準備工作

對getSingleton匿名內部類回調方法代碼的簡化處理

singletonObject = singletonFactory.getObject(){
	createBean(){
		doCreateBean(){
		
			// 實例化bean,將BeanDefinition轉爲BeanWrapper
		    instanceWrapper = createBeanInstance(beanName, mbd, args);
		
		
		    // bean合併後,應用後處理器,如:Autowired註解正式通過此方法實現諸如類型的預解析
			// AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition
			applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
		
		    // 是否允許單例提前暴露
		    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
			
			// 單例&允許循環依賴&正在創建中的單例
			if(earlySingletonExposure){
			    addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory){
					// 將創建bean的singletonFactory,放入緩存
					// getEarlyBeanReference,對bean再一次依賴引用,主要應用SmartInstantiationAwareBeanPostProcessor
					// 我們熟悉的AOP就是在這裏將advice動態織入bean中,如果沒有,則直接返回bean,不做處理
					this.singletonFactories.put(beanName, singletonFactory);
					
					this.earlySingletonObjects.remove(beanName);
					this.registeredSingletons.add(beanName);
				}
			}

            // bean的屬性填充,
			populateBean(){
				// 這裏會將當前bean所需的依賴進行實例化,getBean(propertyValue),並填充
				// 舉例A類某字段依賴B,那麼在A還未完成實例化前,在填充屬性階段,會優先實例化A的字段B,此時Abean存儲在singletonFactories中
				// 如果恰好B類中某字段依賴A,循環出現了,如何解決?
				// 還記得上述首次獲取單例的代碼?依次從singletonObjects-->earlySingletonObjects-->singletonFactories
				// 這樣A類的依賴B就可以拿到自己的依賴A的實例,此處實例不是完全的,但與最終單例A的地址是一樣的,當A實例完成後,那麼B類中引用的A的實例也是全部完成實例化的
			}
			
			// 通過bean初始化進行擴展
			initializeBean(){
			    // 爲當前bean獲取一些相對應的資源,調用Aware,如BeanFactoryAware,
				invokeAwareMethods
				// 在調用客戶自定義初始化前,利用BeanPostProcessors自定義擴展,
				applyBeanPostProcessorsBeforeInitialization
				// 調用用戶自定的初始化邏輯
				invokeInitMethods{
				    // 優先調用afterPropertiesSet
				    ((InitializingBean) bean).afterPropertiesSet()
				    // 調用用戶自定義的init-method
				    invokeCustomInitMethod(beanName, bean, mbd);
				}
				// 在調用客戶自定義初始化後,利用BeanPostProcessors自定義擴展
				applyBeanPostProcessorsAfterInitialization
			}
			
			// 對已經實例化的bean進行循環依賴檢查
			if(earlySingletonExposure){
			    // 查看當前bean是否被詢依賴,當前bean正在創建中,不會出現在singletonObjects緩存中,
    			// 假設當前bean沒有被依賴,則當前bean實例一定在singletonFactories中,
    			// 如果被依賴,則當前bean實例因爲需要加載,則會在緩存中查找,當查找後,會將singletonFactories中的工廠生產的實例存放在earlySingletonObjects單例緩存中,
    
    			// 爲了檢測是否有循環依賴,只需要查詢earlySingletonObjects單例緩存中是否存在當前bean的實例,那麼參數allowEarlyReference爲false
			    Object earlySingletonReference = getSingleton(beanName, false){
			        // 省略相關單例緩存從中獲取實例的邏輯,詳情參看getSingleton()代碼
			        if (singletonObject == null && allowEarlyReference) {
        				// 將創建bean的singletonFactory,放入緩存
        				this.earlySingletonObjects.put(beanName, singletonObject);
        				this.singletonFactories.remove(beanName);
    				}
    			}
    			
    			
        		// 如果earlySingletonReference不爲空,則發生了循環依賴,
				// 那麼需要檢查當前實例與初始化後的實例是否一樣,
				// 如果一樣,則可以直接返回使用,
				// 如果不一樣,則需要檢查是否有未完成依賴的屬性
    			if (earlySingletonReference != null) {
    				if (exposedObject == bean) {
    					exposedObject = earlySingletonReference;
    			} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
    					// 獲取當前bean的依賴
    					String[] dependentBeans = getDependentBeans(beanName);
    					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
    					for (String dependentBean : dependentBeans) {
    						// 如果當前依賴並沒有實例化,沒有出現在已經創建實例的bean緩存中(!this.alreadyCreated.contains(beanName))
    						// 什麼時候將bean記錄到alreadyCreated中呢?參考AbstractBeanFactory.doGetBean-->AbstractBeanFactory.markBeanAsCreated
    						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
    							actualDependentBeans.add(dependentBean);
    						}
    					}
                        // 如果存在沒有實例化的依賴,則說明當前bean實例化失敗,
    					if (!actualDependentBeans.isEmpty()) {
    						throw new BeanCurrentlyInCreationException(beanName,
    								"Bean with name '" + beanName + "' has been injected into other beans [" +
    								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
    								"] in its raw version as part of a circular reference, but has eventually been " +
    								"wrapped. This means that said other beans do not use the final version of the " +
    								"bean. This is often the result of over-eager type matching - consider using " +
    								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
    					}
    				}
    			}
    			
			}
			// 註冊DisposableBean,如果配置了destroy-method,這裏需要註冊,便於在銷燬bean調用
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
	}
}

總結doCreateBean處理邏輯流程:

  • 2.1、實例化bean,將BeanDefinition轉爲BeanWrapper
  • 2.2、bean合併後的後處理器
  • 2.3、允許單例提前暴露,將生產bean的bean工廠添加到singletonFactory單例緩存中
  • 2.4、bean的屬性填充,
  • 2.5、通過bean初始化進行擴展
  • 2.6、對已經實例化的bean進行循環依賴檢查
  • 2.7、註冊DisposableBean,銷燬bean時回調

對於單例循環依賴, 我們最關注的是第3、6步,第3步,將創建bean的bean工廠添加到singletonFactory單例緩存中,提前暴露單例,第6步、查看當前已經初始化的bean的是否有循環依賴

3、移除當前bean創建中狀態

將當前正在創建中的bean從singletonsCurrentlyInCreation單例緩存池中移除

4、緩存當前創建完後的bean實例

將當前bean實例添加到singletonObjects單例緩存中

至此,涉及到的幾個單例緩存池已經全部用到了,那麼是如何解決單例setter循環依賴呢?

解決循環依賴

用一個簡單舉例,A依賴B,B依賴A情況,分析他們的加載過程,來回顧一下bean加載過程中,幾個單例緩存池的應用,以及如何解決循環依賴的

@Component
pubilc Class A{
    @Autowired
    private B b;
    
    // getter & setter
}
@Component
public Class B{
    @Autowired
    private A a;
    
    // getter & setter
}

首次加載A的時候,沒有緩存,先將beanA放入到singletonsCurrentlyInCreation單例緩存池,接着講創建A的工廠放入到singletonFactories單例緩存池中,接着實例A在填充它的屬性B的時候發現依賴B,於是getBean(beanB), 開始加載B

首次加載B的時候,沒有緩存,先將beanB放入到singletonsCurrentlyInCreation單例緩存池,接着將創建B的工廠放入到singletonFactories單例緩存池中,接着實例B在填充它的屬性A的時候發現依賴A,於是getBean(beanA), 開始加載A

第二次加載A,由於之前已經放到單例緩存池中了,所有進入緩存中查找,執行getSingleton(String beanName)–>getSingleton(beanName, true)的邏輯,第二參數允許早起循環引用,首先查找singletonObject單例緩存池,發現沒有,因爲此時beanA還未創建成功,接着根據條件判斷,沒有在singletonObject緩存池中獲取到實例且當前beanA正在創建中,所以從earlySingletonObjects緩存池中獲取(this.earlySingletonObjects.get(beanName)),發現仍然沒有, 接着從singletonFactories緩存池中查找,發現不爲空並且允許早起循環引用,於是根據當前工廠獲取bean實例,並將實例添加到earlySingletonObjects緩存池中,並從singletonFactories單例緩存池中移除,

由於B的屬性填充過程中獲取到A的實例,雖然此時B屬性中的實例A剛初始化,還未填充屬性,但是它的地址和A的實例地址一樣。這樣就中斷了對實例A的屬性填充,從而避免了循環依賴

B完成屬性填充後,進行初始化,進行依賴循環檢查,則,B初始化完成,從singletonsCurrentlyInCreation單例緩存池中移除beanB,將beanB存放到singletonObjects,並記錄beanB到registeredSingletons單例緩存池中,beanB已經實例化,那麼接着繼續A的屬性填充,當A完成屬性填充,初始化後,從singletonsCurrentlyInCreation單例緩存池中移除beanA,將beanB存放到singletonObjects,並記錄beanA到registeredSingletons單例緩存池中,標識beanA已經實例化。

至此整個與循環依賴的加載完成。理解了bean加載過程中的循環依賴,那麼對於bean的加載,我們就更加清晰

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章