在 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); } // 如果工廠方法不為空,則使用工廠方法初始化策略,這里推薦看Factory-Method實例化Bean 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獲取,這樣就解決了循環依賴的問題。