在 Spring 中存在著不同的 scope,預設是 singleton ,還有 prototype、request 等等其他的 scope,他們的初始化步驟是怎樣的呢?這個答案在這篇部落格中給出。
singleton
Spring 的 scope 預設為 singleton,第一部分分析了從快取中獲取單例模式的 bean,但是如果快取中不存在呢?則需要從頭開始載入 bean,這個過程由 getSingleton()
實現。其初始化的程式碼如下:
if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
這裡我們看到了 java8的新特性lambda表示式 () -> , getSingleton方法的第二個引數為 ObjectFactory<?> singletonFactory,() ->相當於建立了一個ObjectFactory型別的匿名內部類,去實現ObjectFactory介面中的getObject()方法,其中{}中的程式碼相當於寫在匿名內部類中getObject()的程式碼片段,等著getSingleton方法裡面通過ObjectFactory<?> singletonFactory去顯示呼叫,如singletonFactory.getObject()。上述程式碼可以反推成如下程式碼:
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } } });
下面我們進入到 getSingleton方法中
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); // 全域性加鎖 synchronized (this.singletonObjects) { // 從快取中檢查一遍 // 因為 singleton 模式其實就是複用已經建立的 bean 所以這步驟必須檢查 Object singletonObject = this.singletonObjects.get(beanName); // 為空,開始載入過程 if (singletonObject == null) { // 省略 部分程式碼 // 載入前置處理 beforeSingletonCreation(beanName); boolean newSingleton = false; // 省略程式碼 try { // 初始化 bean // 這個過程就是我上面講的呼叫匿名內部類的方法,其實是呼叫 createBean() 方法 singletonObject = singletonFactory.getObject(); newSingleton = true; } // 省略 catch 部分 } finally { // 後置處理 afterSingletonCreation(beanName); } // 加入快取中 if (newSingleton) { addSingleton(beanName, singletonObject); } } // 直接返回 return singletonObject; } }
上述程式碼中其實,使用了回撥方法,使得程式可以在單例建立的前後做一些準備及處理操作,而真正獲取單例bean的方法其實並不是在此方法中實現的,其實現邏輯是在ObjectFactory型別的例項singletonFactory中實現的(即上圖貼上的第一段程式碼)。而這些準備及處理操作包括如下內容。
(1)檢查快取是否已經載入過
(2)如果沒有載入,則記錄beanName的正在載入狀態
(3)載入單例前記錄載入狀態。 可能你會覺得beforeSingletonCreation方法是個空實現,裡面沒有任何邏輯,但其實這個函式中做了一個很重要的操作:記錄載入狀態,也就是通過this.singletonsCurrentlyInCreation.add(beanName)將當前正要建立的bean記錄在快取中,這樣便可以對迴圈依賴進行檢測。 我們上一篇文章已經講過,可以去看看。
(4)通過呼叫引數傳入的ObjectFactory的個體Object方法例項化bean.
(5)載入單例後的處理方法呼叫。 同步驟3的記錄載入狀態相似,當bean載入結束後需要移除快取中對該bean的正在載入狀態的記錄。
(6)將結果記錄至快取並刪除載入bean過程中所記錄的各種輔助狀態。
(7)返回處理結果
我們看另外一個方法 addSingleton()
。
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
一個 put、一個 add、兩個 remove。singletonObjects 單例 bean 的快取,singletonFactories 單例 bean Factory 的快取,earlySingletonObjects “早期”建立的單例 bean 的快取,registeredSingletons 已經註冊的單例快取。
載入了單例 bean 後,呼叫 getObjectForBeanInstance()
從 bean 例項中獲取物件。該方法我們在上一篇中已經講過。
原型模式
else if (mbd.isPrototype()) { Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); }
原型模式的初始化過程很簡單:直接建立一個新的例項就可以了。過程如下:
- 呼叫
beforeSingletonCreation()
記錄載入原型模式 bean 之前的載入狀態,即前置處理。 - 呼叫
createBean()
建立一個 bean 例項物件。 - 呼叫
afterSingletonCreation()
進行載入原型模式 bean 後的後置處理。 - 呼叫
getObjectForBeanInstance()
從 bean 例項中獲取物件。
其他作用域
String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); }
核心流程和原型模式一樣,只不過獲取 bean 例項是由 scope.get()
實現,如下:
public Object get(String name, ObjectFactory<?> objectFactory) { // 獲取 scope 快取 Map<String, Object> scope = this.threadScope.get(); Object scopedObject = scope.get(name); if (scopedObject == null) { scopedObject = objectFactory.getObject(); // 加入快取 scope.put(name, scopedObject); } return scopedObject; }
對於上面三個模組,其中最重要的方法,是 createBean(),也就是核心建立bean的過程,下面我們來具體看看。
準備建立bean
if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
如上所示,createBean是真正建立bean的地方,此方法是定義在AbstractAutowireCapableBeanFactory中,我們看下其原始碼:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { if (logger.isDebugEnabled()) { logger.debug("Creating instance of bean '" + beanName + "'"); } RootBeanDefinition mbdToUse = mbd; // 確保此時的 bean 已經被解析了 // 如果獲取的class 屬性不為null,則克隆該 BeanDefinition // 主要是因為該動態解析的 class 無法儲存到到共享的 BeanDefinition Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } try { // 驗證和準備覆蓋方法 mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { // 給 BeanPostProcessors 一個機會用來返回一個代理類而不是真正的類例項 // AOP 的功能就是基於這個地方 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } catch (Throwable ex) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); } try { // 執行真正建立 bean 的過程 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException( mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); } }
例項化的前置處理
resolveBeforeInstantiation()
的作用是給 BeanPostProcessors 後置處理器返回一個代理物件的機會,其實在呼叫該方法之前 Spring 一直都沒有建立 bean ,那麼這裡返回一個 bean 的代理類有什麼作用呢?作用體現在後面的 if
判斷:
if (bean != null) { return bean; }
如果代理物件不為空,則直接返回代理物件,這一步驟有非常重要的作用,Spring 後續實現 AOP 就是基於這個地方判斷的。
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { Object bean = null; if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<?> targetType = determineTargetType(beanName, mbd); if (targetType != null) { bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); if (bean != null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean != null); } return bean; }
這個方法核心就在於 applyBeanPostProcessorsBeforeInstantiation()
和 applyBeanPostProcessorsAfterInitialization()
兩個方法,before 為例項化前的後處理器應用,after 為例項化後的後處理器應用,由於本文的主題是建立 bean,關於 Bean 的增強處理後續 LZ 會單獨出博文來做詳細說明。
建立 bean
如果沒有代理物件,就只能走常規的路線進行 bean 的建立了,該過程有 doCreateBean()
實現,如下:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // BeanWrapper是對Bean的包裝,其介面中所定義的功能很簡單包括設定獲取被包裝的物件,獲取被包裝bean的屬性描述器 BeanWrapper instanceWrapper = null; // 單例模型,則從未完成的 FactoryBean 快取中刪除 if (mbd.isSingleton()) {anceWrapper = this.factoryBeanInstanceCache.remove(beanName); } // 使用合適的例項化策略來建立新的例項:工廠方法、建構函式自動注入、簡單初始化 if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } // 包裝的例項物件 final Object bean = instanceWrapper.getWrappedInstance(); // 包裝的例項物件的型別 Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // 檢測是否有後置處理 // 如果有後置處理,則允許後置處理修改 BeanDefinition synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { // applyMergedBeanDefinitionPostProcessors // 後置處理修改 BeanDefinition applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } } // 解決單例模式的迴圈依賴 // 單例模式 & 允許迴圈依賴&當前單例 bean 是否正在被建立 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } // 提前將建立的 bean 例項加入到ObjectFactory 中 // 這裡是為了後期避免迴圈依賴 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } /* * 開始初始化 bean 例項物件 */ Object exposedObject = bean; try { // 對 bean 進行填充,將各個屬性值注入,其中,可能存在依賴於其他 bean 的屬性 // 則會遞迴初始依賴 bean populateBean(beanName, mbd, instanceWrapper); // 呼叫初始化方法,比如 init-method exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } /** * 迴圈依賴處理 */ if (earlySingletonExposure) { // 獲取 earlySingletonReference Object earlySingletonReference = getSingleton(beanName, false); // 只有在存在迴圈依賴的情況下,earlySingletonReference 才不會為空 if (earlySingletonReference != null) { // 如果 exposedObject 沒有在初始化方法中被改變,也就是沒有被增強 if (exposedObject == bean) { exposedObject = earlySingletonReference; } // 處理依賴 else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } 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."); } } } } try { // 註冊 bean registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
大概流程如下:
createBeanInstance()
例項化 beanpopulateBean()
屬性填充- 迴圈依賴的處理
initializeBean()
初始化 bean
createBeanInstance
我們首先從createBeanInstance方法開始。方法程式碼如下:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 解析 bean,將 bean 類名解析為 class 引用 Class<?> beanClass = resolveBeanClass(mbd, beanName); if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); } // 如果存在 Supplier 回撥,則使用給定的回撥方法初始化策略 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } // 如果工廠方法不為空,則使用工廠方法初始化策略 if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } boolean resolved = false; boolean autowireNecessary = false; if (args == null) { // constructorArgumentLock 建構函式的常用鎖 synchronized (mbd.constructorArgumentLock) { // 如果已快取的解析的建構函式或者工廠方法不為空,則可以利用建構函式解析 // 因為需要根據引數確認到底使用哪個建構函式,該過程比較消耗效能,所有采用快取機制 if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } // 已經解析好了,直接注入即可 if (resolved) { // 自動注入,呼叫建構函式自動注入 if (autowireNecessary) { return autowireConstructor(beanName, mbd, null, null); } else { // 使用預設建構函式構造 return instantiateBean(beanName, mbd); } } // 確定解析的建構函式 // 主要是檢查已經註冊的 SmartInstantiationAwareBeanPostProcessor Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { // 建構函式自動注入 return autowireConstructor(beanName, mbd, ctors, args); } //使用預設建構函式注入 return instantiateBean(beanName, mbd); }
例項化 bean 是一個複雜的過程,其主要的邏輯為:
- 如果存在 Supplier 回撥,則呼叫
obtainFromSupplier()
進行初始化 - 如果存在工廠方法,則使用工廠方法進行初始化
- 首先判斷快取,如果快取中存在,即已經解析過了,則直接使用已經解析了的,根據 constructorArgumentsResolved 引數來判斷是使用建構函式自動注入還是預設建構函式
- 如果快取中沒有,則需要先確定到底使用哪個建構函式來完成解析工作,因為一個類有多個建構函式,每個建構函式都有不同的構造引數,所以需要根據引數來鎖定建構函式並完成初始化,如果存在引數則使用相應的帶有引數的建構函式,否則使用預設建構函式。
instantiateBean
不帶引數的建構函式的例項化過程使用的方法是instantiateBean(beanName, mbd),我們看下原始碼:
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this; if (System.getSecurityManager() != null) { beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, parent), getAccessControlContext()); } else { beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); } BeanWrapper bw = new BeanWrapperImpl(beanInstance); initBeanWrapper(bw); return bw; } catch (Throwable ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); } }
例項化策略
例項化過程中,反覆提到了例項化策略,這是做什麼的呢?其實,經過前面的分析,我們已經得到了足以例項化的相關資訊,完全可以使用最簡單的反射方法來構造例項物件,但Spring卻沒有這麼做。
接下來我們看下Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)方法,具體的實現是在SimpleInstantiationStrategy中,具體程式碼如下:
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // 沒有覆蓋 // 直接使用反射例項化即可 if (!bd.hasMethodOverrides()) { // 重新檢測獲取下建構函式 // 該建構函式是經過前面 N 多複雜過程確認的建構函式 Constructor<?> constructorToUse; synchronized (bd.constructorArgumentLock) { // 獲取已經解析的建構函式 constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; // 如果為 null,從 class 中解析獲取,並設定 if (constructorToUse == null) { final Class<?> clazz = bd.getBeanClass(); if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { if (System.getSecurityManager() != null) { constructorToUse = AccessController.doPrivileged( (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor); } else { //利用反射獲取構造器 constructorToUse = clazz.getDeclaredConstructor(); } bd.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Throwable ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } // 通過BeanUtils直接使用構造器物件例項化bean return BeanUtils.instantiateClass(constructorToUse); } else { // 生成CGLIB建立的子類物件 return instantiateWithMethodInjection(bd, beanName, owner); } }
如果該 bean 沒有配置 lookup-method、replaced-method 標籤或者 @Lookup 註解,則直接通過反射的方式例項化 bean 即可,方便快捷,但是如果存在需要覆蓋的方法或者動態替換的方法則需要使用 CGLIB 進行動態代理,因為可以在建立代理的同時將動態方法織入類中。
呼叫工具類 BeanUtils 的 instantiateClass()
方法完成反射工作:
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException { Assert.notNull(ctor, "Constructor must not be null"); try { ReflectionUtils.makeAccessible(ctor); return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ? KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args)); } // 省略一些 catch }
CGLIB
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy"); }
方法預設是沒有實現的,具體過程由其子類 CglibSubclassingInstantiationStrategy 實現:
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { return instantiateWithMethodInjection(bd, beanName, owner, null); } protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, @Nullable Constructor<?> ctor, @Nullable Object... args) { // 通過CGLIB生成一個子類物件 return new CglibSubclassCreator(bd, owner).instantiate(ctor, args); }
建立一個 CglibSubclassCreator 物件,呼叫其 instantiate()
方法生成其子類物件:
public Object instantiate(@Nullable Constructor<?> ctor, @Nullable Object... args) { // 通過 Cglib 建立一個代理類 Class<?> subclass = createEnhancedSubclass(this.beanDefinition); Object instance; // 沒有構造器,通過 BeanUtils 使用預設構造器建立一個bean例項 if (ctor == null) { instance = BeanUtils.instantiateClass(subclass); } else { try { // 獲取代理類對應的構造器物件,並例項化 bean Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes()); instance = enhancedSubclassConstructor.newInstance(args); } catch (Exception ex) { throw new BeanInstantiationException(this.beanDefinition.getBeanClass(), "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex); } } // 為了避免memory leaks異常,直接在bean例項上設定回撥物件 Factory factory = (Factory) instance; factory.setCallbacks(new Callback[] {NoOp.INSTANCE, new CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor(this.beanDefinition, this.owner), new CglibSubclassingInstantiationStrategy.ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)}); return instance; }
當然這裡還沒有具體分析 CGLIB 生成子類的詳細過程,具體的過程等後續分析 AOP 的時候再詳細地介紹。
記錄建立bean的ObjectFactory
在剛剛建立完Bean的例項後,也就是剛剛執行完構造器例項化後,doCreateBean方法中有下面一段程式碼:
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } //為避免後期迴圈依賴,可以在bean初始化完成前將建立例項的ObjectFactory加入工廠 //依賴處理:在Spring中會有迴圈依賴的情況,例如,當A中含有B的屬性,而B中又含有A的屬性時就會 //構成一個迴圈依賴,此時如果A和B都是單例,那麼在Spring中的處理方式就是當建立B的時候,涉及 //自動注入A的步驟時,並不是直接去再次建立A,而是通過放入快取中的ObjectFactory來建立例項, //這樣就解決了迴圈依賴的問題。 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); }
isSingletonCurrentlyInCreation(beanName):該bean是否在建立中。在Spring中,會有個專門的屬性預設為DefaultSingletonBeanRegistry的singletonsCurrentlyInCreation來記錄bean的載入狀態,在bean開始建立前會將beanName記錄在屬性中,在bean建立結束後會將beanName移除。那麼我們跟隨程式碼一路走下來可以對這個屬性的記錄並沒有多少印象,這個狀態是在哪裡記錄的呢?不同scope的記錄位置不一樣,我們以singleton為例,在singleton下記錄屬性的函式是在DefaultSingletonBeanRegistry類的public Object getSingleton(String beanName,ObjectFactory singletonFactory)函式的beforeSingletonCreation(beanName)和afterSingletonCreation(beanName)中,在這兩段函式中分別this.singletonsCurrentlyInCreation.add(beanName)與this.singletonsCurrentlyInCreation.remove(beanName)來進行狀態的記錄與移除。
變數earlySingletonExposure是否是單例,是否允許迴圈依賴,是否對應的bean正在建立的條件的綜合。當這3個條件都滿足時會執行addSingletonFactory操作,那麼加入SingletonFactory的作用是什麼?又是在什麼時候呼叫的?
我們還是以最簡單AB迴圈為例,類A中含有屬性B,而類B中又會含有屬性A,那麼初始化beanA的過程如下:
上圖展示了建立BeanA的流程,在建立A的時候首先會記錄類A所對應額beanName,並將beanA的建立工廠加入快取中,而在對A的屬性填充也就是呼叫pupulateBean方法的時候又會再一次的對B進行遞迴建立。同樣的,因為在B中同樣存在A屬性,因此在例項化B的populateBean方法中又會再次地初始化B,也就是圖形的最後,呼叫getBean(A).關鍵是在這裡,我們之前分析過,在這個函式中並不是直接去例項化A,而是先去檢測快取中是否有已經建立好的對應的bean,或者是否已經建立的ObjectFactory,而此時對於A的ObjectFactory我們早已經建立,所以便不會再去向後執行,而是直接呼叫ObjectFactory去建立A.這裡最關鍵的是ObjectFactory的實現。
其中getEarlyBeanReference的程式碼如下:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); if (exposedObject == null) { return exposedObject; } } } } return exposedObject; }
在getEarlyBeanReference函式中除了後處理的呼叫外沒有別的處理工作,根據分析,基本可以理清Spring處理迴圈依賴的解決辦法,在B中建立依賴A時通過ObjectFactory提供的例項化方法來獲取原始A,使B中持有的A僅僅是剛剛初始化並沒有填充任何屬性的A,而這初始化A的步驟還是剛剛建立A時進行的,但是因為A與B中的A所表示的屬性地址是一樣的所以在A中建立好的屬性填充自然可以通過B中的A獲取,這樣就解決了迴圈依賴的問題。