在 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);
}
原型模式的初始化過程很簡單:直接建立一個新的執行個體就可以了。過程如下:
- 調用
記錄加載原型模式 bean 之前的加載狀态,即前置處理。beforeSingletonCreation()
- 調用
建立一個 bean 執行個體對象。createBean()
- 調用
進行加載原型模式 bean 後的後置處理。afterSingletonCreation()
- 調用
從 bean 執行個體中擷取對象。getObjectForBeanInstance()
其他作用域
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;
}
大概流程如下:
-
執行個體化 beancreateBeanInstance()
-
屬性填充populateBean()
- 循環依賴的處理
-
初始化 beaninitializeBean()
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擷取,這樣就解決了循環依賴的問題。