該系列文章是本人在學習 Spring 的過程中總結下來的,裡面涉及到相關原始碼,可能對讀者不太友好,請結合我的原始碼註釋 Spring 原始碼分析 GitHub 地址 進行閱讀
Spring 版本:5.1.14.RELEASE
開始閱讀這一系列文章之前,建議先檢視《深入瞭解 Spring IoC(面試題)》這一篇文章
該系列其他文章請檢視:《死磕 Spring 之 IoC 篇 - 文章導讀》
Bean 的建立過程
上一篇《開啟 Bean 的載入》文章分析了 Bean 的整個載入過程,當我們顯示或者隱式地呼叫AbstractBeanFactory
的 getBean(...)
方法時,會觸發 Bean 的載入,會進行一系列的處理,具體實現可檢視上一篇文章。
對於不同作用域的 Bean,底層都會呼叫 AbstractAutowireCapableBeanFactory
的 createBean(...)
方法進行建立,建立 Bean 的過程涉及到 Bean 生命週期的大部分階段,例如例項化階段、屬性賦值階段、Aware 介面回撥階段、初始化階段都是在這個方法中完成的,這個核心方法在上一篇文章沒有講述,接下來將在本文進行分析。
AbstractAutowireCapableBeanFactory
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
抽象類,繼承 AbstractBeanFactory,實現 AutowireCapableBeanFactory 介面,完成 Bean 的建立
【核心】createBean 方法
createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
方法,建立 Bean,方法如下:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
// <1> 獲取 `mbd` 對應的 Class 物件,確保當前 Bean 能夠被建立出來
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
// 如果這裡獲取到了 Class 物件,但是 `mbd` 中沒有 Class 物件的相關資訊,表示這個 Class 物件是動態解析出來的
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
// 複製一份 `mbd`,並設定 Class 物件,因為動態解析出來的 Class 物件不被共享
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
// <2> 對所有的 MethodOverride 進行驗證和準備工作(確儲存在對應的方法,並設定為不能重複載入)
mbdToUse.prepareMethodOverrides();
} catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
/**
* <3> 在例項化前進行相關處理,會先呼叫所有 {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation}
* 注意,如果這裡返回物件不是 `null` 的話,不會繼續往下執行原本初始化操作,直接返回,也就是說這個方法返回的是最終例項物件
* 可以通過這種方式提前返回一個代理物件,例如 AOP 的實現,或者 RPC 遠端呼叫的實現(因為本地類沒有遠端能力,可以通過這種方式進行攔截)
*/
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 {
// <4> 建立 Bean 物件 `beanInstance`,如果上一步沒有返回代理物件,就只能走常規的路線進行 Bean 的建立了
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
// <5> 將 `beanInstance` 返回
return beanInstance;
} catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
入參:
beanName
:Bean 的名稱mbd
:Bean 的 BeanDefinition 物件(合併後)args
:建立 Bean 的引數,我們通常不會傳,所以這裡為null
過程大致如下:
-
獲取
mbd
對應的 Class 物件,確保當前 Bean 能夠被建立出來,呼叫resolveBeanClass(...)
方法 -
對所有的 MethodOverride 進行驗證和準備工作(確儲存在對應的方法,並設定為不能重複載入)
-
例項化前階段在例項化前進行相關處理,會先呼叫所有 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
注意,如果這裡返回物件不是
null
的話,不會繼續往下執行原本初始化操作,直接返回,也就是說這個方法返回的是最終例項物件可以通過這種方式提前返回一個代理物件,例如 AOP 的實現,或者 RPC 遠端呼叫的實現(因為本地類沒有遠端能力,可以通過這種方式進行攔截)
-
建立 Bean 物件
beanInstance
,如果上一步沒有返回代理物件,就只能走常規的路線進行 Bean 的建立了,呼叫doCreateBean(...)
方法 -
將
beanInstance
返回
可以看到這個方法中並沒有開始真正 Bean 的建立,在這個方法的第 4
步會呼叫 doCreateBean(...)
方法建立 Bean
【核心】doCreateBean 方法
doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
,建立 Bean,方法如下:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
/**
* <1> Bean 的例項化階段,會將 Bean 的例項物件封裝成 {@link BeanWrapperImpl} 包裝物件
* BeanWrapperImpl 承擔的角色:
* 1. Bean 例項的包裝
* 2. {@link org.springframework.beans.PropertyAccessor} 屬性編輯器
* 3. {@link org.springframework.beans.PropertyEditorRegistry} 屬性編輯器登錄檔
* 4. {@link org.springframework.core.convert.ConversionService} 型別轉換器(Spring 3+,替換了之前的 TypeConverter)
*/
BeanWrapper instanceWrapper = null;
// <1.1> 如果是單例模式,則先嚐試從 `factoryBeanInstanceCache` 快取中獲取例項物件,並從快取中移除
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// <1.2> 使用合適的例項化策略來建立 Bean 的例項:工廠方法、建構函式自動注入、簡單初始化
// 主要是將 BeanDefinition 轉換為 BeanWrapper 物件
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// <1.3> 獲取包裝的例項物件 `bean`
final Object bean = instanceWrapper.getWrappedInstance();
// <1.4> 獲取包裝的例項物件的型別 `beanType`
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
// <2> 對 RootBeanDefinition(合併後)進行加工處理
synchronized (mbd.postProcessingLock) { // 加鎖,執行緒安全
// <2.1> 如果該 RootBeanDefinition 沒有處理過,則進行下面的處理
if (!mbd.postProcessed) {
try {
/**
* <2.2> 對 RootBeanDefinition(合併後)進行加工處理
* 呼叫所有 {@link MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition}
* 【重要】例如有下面兩個處理器:
* 1. AutowiredAnnotationBeanPostProcessor 會先解析出 @Autowired 和 @Value 註解標註的屬性的注入元資訊,後續進行依賴注入;
* 2. CommonAnnotationBeanPostProcessor 會先解析出 @Resource 註解標註的屬性的注入元資訊,後續進行依賴注入,
* 它也會找到 @PostConstruct 和 @PreDestroy 註解標註的方法,並構建一個 LifecycleMetadata 物件,用於後續生命週期中的初始化和銷燬
*/
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
// <2.3> 設定該 RootBeanDefinition 被處理過,避免重複處理
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// <3> 提前暴露這個 `bean`,如果可以的話,目的是解決單例模式 Bean 的迴圈依賴注入
// <3.1> 判斷是否可以提前暴露
boolean earlySingletonExposure = (mbd.isSingleton() // 單例模式
&& this.allowCircularReferences // 允許迴圈依賴,預設為 true
&& isSingletonCurrentlyInCreation(beanName)); // 當前單例 bean 正在被建立,在前面已經標記過
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
/**
* <3.2>
* 建立一個 ObjectFactory 實現類,用於返回當前正在被建立的 `bean`,提前暴露,儲存在 `singletonFactories` (**三級 Map**)快取中
*
* 可以回到前面的 {@link AbstractBeanFactory#doGetBean#getSingleton(String)} 方法
* 載入 Bean 的過程會先從快取中獲取單例 Bean,可以避免單例模式 Bean 迴圈依賴注入的問題
*/
addSingletonFactory(beanName,
// ObjectFactory 實現類
() -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
// 開始初始化 `bean`
Object exposedObject = bean;
try {
// <4> 對 `bean` 進行屬性填充,注入對應的屬性值
populateBean(beanName, mbd, instanceWrapper);
// <5> 初始化這個 `exposedObject`,呼叫其初始化方法
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);
}
}
// <6> 迴圈依賴注入的檢查
if (earlySingletonExposure) {
// <6.1> 獲取當前正在建立的 `beanName` 被依賴注入的早期引用
// 注意,這裡有一個入參是 `false`,不會呼叫上面第 `3` 步的 ObjectFactory 實現類
// 也就是說當前 `bean` 如果出現迴圈依賴注入,這裡才能獲取到提前暴露的引用
Object earlySingletonReference = getSingleton(beanName, false);
// <6.2> 如果出現了迴圈依賴注入,則進行接下來的檢查工作
if (earlySingletonReference != null) {
// <6.2.1> 如果 `exposedObject` 沒有在初始化階段中被改變,也就是沒有被增強
// 則使用提前暴露的那個引用
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// <6.2.2> 否則,`exposedObject` 已經不是被別的 Bean 依賴注入的那個 Bean
else if (!this.allowRawInjectionDespiteWrapping // 是否允許注入未加工的 Bean,預設為 false,這裡取非就為 true
&& hasDependentBean(beanName)) { // 存在依賴 `beanName` 的 Bean(通過 `depends-on` 配置)
// 獲取依賴當前 `beanName` 的 Bean 們的名稱(通過 `depends-on` 配置)
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
// 接下來進行判斷,如果依賴 `beanName` 的 Bean 已經建立
// 說明當前 `beanName` 被注入了,而這裡最終的 `bean` 被包裝過,不是之前被注入的
// 則丟擲異常
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.");
}
}
}
}
// Register bean as disposable.
try {
/**
* <7> 為當前 `bean` 註冊 DisposableBeanAdapter(如果需要的話),用於 Bean 生命週期中的銷燬階段
* 可以看到 {@link DefaultSingletonBeanRegistry#destroySingletons()} 方法
*/
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
// <8> 返回建立好的 `exposedObject` 物件
return exposedObject;
}
這個方法的處理過程有點長,如下:
-
Bean 的例項化階段,會將 Bean 的例項物件封裝成 BeanWrapperImpl 包裝物件
-
如果是單例模式,則先嚐試從
factoryBeanInstanceCache
快取中獲取例項物件,並從快取中移除 -
使用合適的例項化策略來建立 Bean 的例項:工廠方法、建構函式自動注入、簡單初始化,主要是將 BeanDefinition 轉換為 BeanWrapper 物件
呼叫
createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
方法 -
獲取包裝的例項物件
bean
-
獲取包裝的例項物件的型別
beanType
-
-
對 RootBeanDefinition(合併後)進行加工處理
- 如果該 RootBeanDefinition 沒有處理過,則進行下面的處理
- 呼叫所有的 MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition,這個過程非常重要,例如 Spring 內有下面兩個處理器:
- AutowiredAnnotationBeanPostProcessor,會先解析出
@Autowired
和@Value
註解標註的屬性的注入元資訊,後續進行依賴注入 - CommonAnnotationBeanPostProcessor,會先解析出
@Resource
註解標註的屬性的注入元資訊,後續進行依賴注入,它也會找到@PostConstruct
和@PreDestroy
註解標註的方法,並構建一個 LifecycleMetadata 物件,用於後續生命週期中的初始化和銷燬
- AutowiredAnnotationBeanPostProcessor,會先解析出
- 設定該 RootBeanDefinition 被處理過,避免重複處理
-
提前暴露這個
bean
,如果可以的話,目的是解決單例模式 Bean 的迴圈依賴注入- 判斷是否可以提前暴露,滿足三個條件:單例模式、允許迴圈依賴(預設為 true)、當前單例 bean 正在被建立,在前面已經標記過
- 建立一個 ObjectFactory 實現類,用於返回當前正在被建立的
bean
,提前暴露,儲存在singletonFactories
(三級 Map)快取中
接下來開始初始化上面的 bean
例項物件,會先建立一個 Object exposedObject
等於 bean
(引用)
- 對
bean
進行屬性填充,注入對應的屬性值,呼叫populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
方法 - 初始化這個
exposedObject
,呼叫其初始化方法,呼叫initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
方法
-
迴圈依賴注入的檢查
- 獲取當前正在建立的
beanName
被依賴注入的早期引用,呼叫DefaultSingletonBeanRegistry#getSingleton(String beanName, boolean allowEarlyReference)
方法。注意,這裡有一個入參是false
,不會呼叫上面第3
步的 ObjectFactory 實現類,也就是說當前bean
如果出現迴圈依賴注入,這裡才能獲取到提前暴露的引用 - 如果出現了迴圈依賴注入,則進行接下來的檢查工作
- 如果
exposedObject
沒有在初始化階段中被改變,也就是沒有被增強,則使用提前暴露的那個引用 - 否則,
exposedObject
已經不是被別的 Bean 依賴注入的那個 Bean,如果依賴當前beanName
的 Bean(通過depends-on
配置)已經被建立,則丟擲異常
- 如果
- 獲取當前正在建立的
-
為當前
bean
註冊 DisposableBeanAdapter(如果需要的話),用於 Bean 生命週期中的銷燬階段 -
返回建立好的
exposedObject
物件
概括:
- 首先獲取對應的 Class 物件,建立一個例項物件
- 對這個例項物件進行屬性填充
- 呼叫這個例項物件的初始化方法
關於上面建立 Bean 的兩個方法的相關步驟沒有展開討論,下面會依次進行分析
1. 建立 Class 物件
對應程式碼段:
// AbstractAutowireCapableBeanFactory#createBean(...) 方法
// <1> 獲取 `mbd` 對應的 Class 物件,確保當前 Bean 能夠被建立出來
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
// 如果這裡獲取到了 Class 物件,但是 `mbd` 中沒有 Class 物件的相關資訊,表示這個 Class 物件是動態解析出來的
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
// 複製一份 `mbd`,並設定 Class 物件,因為動態解析出來的 Class 物件不被共享
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
建立一個 Java 物件之前,需要確儲存在對應的 Class 物件。如果這裡獲取到了 Class 物件,但是 mbd
中沒有 Class 物件的相關資訊,表示這個 Class 物件是動態解析出來的,則需要複製一份 mbd
,並設定 Class 物件,因為動態解析出來的 Class 物件不被共享
resolveBeanClass 方法
resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
,獲取 beanName
的 Class 物件,方法如下:
// AbstractBeanFactory.java
@Nullable
protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
throws CannotLoadBeanClassException {
try {
// 有 Class 物件則直接返回
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
// 否則,呼叫 `doResolveBeanClass(...)` 方法,載入出一個 Class 物件
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->
doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
} else {
return doResolveBeanClass(mbd, typesToMatch);
}
}
// ... 省略 catch 各種異常
}
如果有 Class 物件則直接返回,沒有的話呼叫 doResolveBeanClass(...)
方法去獲取 Class 物件
doResolveBeanClass 方法
// AbstractBeanFactory.java
@Nullable
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
throws ClassNotFoundException {
// 獲取 ClassLoader 載入器
ClassLoader beanClassLoader = getBeanClassLoader();
ClassLoader dynamicLoader = beanClassLoader;
boolean freshResolve = false;
if (!ObjectUtils.isEmpty(typesToMatch)) {
// When just doing type checks (i.e. not creating an actual instance yet),
// use the specified temporary class loader (e.g. in a weaving scenario).
ClassLoader tempClassLoader = getTempClassLoader();
if (tempClassLoader != null) {
dynamicLoader = tempClassLoader;
freshResolve = true;
if (tempClassLoader instanceof DecoratingClassLoader) {
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
for (Class<?> typeToMatch : typesToMatch) {
dcl.excludeClass(typeToMatch.getName());
}
}
}
}
// 獲取 `className`
String className = mbd.getBeanClassName();
if (className != null) {
// 根據 BeanExpressionResolver 表示式處理器計算出 `className` 對應的結果
// 可能還是一個類名稱,也可能是一個 Class 物件
Object evaluated = evaluateBeanDefinitionString(className, mbd);
if (!className.equals(evaluated)) {
// A dynamically resolved expression, supported as of 4.2...
if (evaluated instanceof Class) {
return (Class<?>) evaluated;
}
else if (evaluated instanceof String) {
className = (String) evaluated;
freshResolve = true;
}
else {
throw new IllegalStateException("Invalid class name expression result: " + evaluated);
}
}
// 如果被處理過,則根據這個 `className` 建立一個 Class 物件
// 建立的 Class 物件不會設定到 `mbd` 中
if (freshResolve) {
// When resolving against a temporary class loader, exit early in order
// to avoid storing the resolved Class in the bean definition.
if (dynamicLoader != null) {
try {
return dynamicLoader.loadClass(className);
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
}
}
}
return ClassUtils.forName(className, dynamicLoader);
}
}
// Resolve regularly, caching the result in the BeanDefinition...
// 讓 RootBeanDefinition 自己解析出 Class 物件
return mbd.resolveBeanClass(beanClassLoader);
}
暫時忽略上面具體的每個細節,底層會根據 className
通過來載入器獲取對應的 Class 物件,並設定到 RootBeanDefinition
注意,這個過程可能是動態解析出來的,例如 className
是一個表示式,通過 BeanDefinition 表示式解析器解析出來的,然後根據其獲取 Class 物件,這裡是不會設定到 RootBeanDefinition 中
2. MethodOverride 的驗證與準備
對應程式碼段:
// AbstractAutowireCapableBeanFactory#createBean(...) 方法
try {
// <2> 對所有的 MethodOverride 進行驗證和準備工作(確儲存在對應的方法,並設定為不能重複載入)
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
<lookup-method />
和 <replace-method />
標籤會被解析成 LookupOverride 和 ReplaceOverride 物件,用於實現或覆蓋某個方法,這裡會進行驗證和準備工作,過程如下:
// AbstractBeanDefinition.java
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exist and determine their overloaded status.
if (hasMethodOverrides()) { // 如果存在 `methodOverrides`
// 獲取所有的 override method,遍歷進行處理
getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
}
}
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
}
else if (count == 1) {
// Mark override as not overloaded, to avoid the overhead of arg type checking.
mo.setOverloaded(false);
}
}
確保這個類中存在對應的方法,並設定為不能重複載入
3. 例項化前階段
對應程式碼段:
// AbstractAutowireCapableBeanFactory#createBean(...) 方法
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
/**
* <3> 在例項化前進行相關處理,會先呼叫所有 {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation}
* 注意,如果這裡返回物件不是 `null` 的話,不會繼續往下執行原本初始化操作,直接返回,也就是說這個方法返回的是最終例項物件
* 可以通過這種方式提前返回一個代理物件,例如 AOP 的實現,或者 RPC 遠端呼叫的實現(因為本地類沒有遠端能力,可以通過這種方式進行攔截)
*/
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);
}
在開始建立 Bean 執行,呼叫 resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd)
方法進行處理,嘗試獲取一個代理物件
注意,如果這裡返回物件不是 null
的話,不會繼續往下執行原本初始化操作,直接返回,也就是說這個方法返回的是最終例項物件。可以通過這種方式提前返回一個代理物件,例如 AOP 的實現,或者 RPC 遠端呼叫的實現(因為本地類沒有遠端能力,可以通過這種方式進行攔截)
resolveBeforeInstantiation 方法
// AbstractAutowireCapableBeanFactory.java
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
// 如果 RootBeanDefinition 不是使用者定義的(由 Spring 解析出來的),並且存在 InstantiationAwareBeanPostProcessor 處理器
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;
}
如果 RootBeanDefinition 不是使用者定義的(由 Spring 解析出來的),並且存在 InstantiationAwareBeanPostProcessor 處理器,則進行下面的處理:
-
例項化前置處理,呼叫
applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)
方法,如下:@Nullable protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); if (result != null) { return result; } } } return null; }
遍歷所有的 InstantiationAwareBeanPostProcessor 處理器,執行 postProcessBeforeInstantiation 方法,例項化前置處理,如果有一個處理後返回的結果不為空則直接返回
-
如果第
1
步返回的物件不為空,則呼叫applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
方法,如下:// AbstractAutowireCapableBeanFactory.java @Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; // 遍歷 BeanPostProcessor for (BeanPostProcessor processor : getBeanPostProcessors()) { // 處理 Object current = processor.postProcessAfterInitialization(result, beanName); // 返回空,則返回 result if (current == null) { return result; } // 修改 result result = current; } return result; }
遍歷所有的 BeanPostProcessor 處理器,執行 postProcessAfterInitialization 方法,初始化後置處理
4. Bean 的例項化
對應程式碼段:
// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Instantiate the bean.
/**
* <1> Bean 的例項化階段,會將 Bean 的例項物件封裝成 {@link BeanWrapperImpl} 包裝物件
* BeanWrapperImpl 承擔的角色:
* 1. Bean 例項的包裝
* 2. {@link org.springframework.beans.PropertyAccessor} 屬性編輯器
* 3. {@link org.springframework.beans.PropertyEditorRegistry} 屬性編輯器登錄檔
* 4. {@link org.springframework.core.convert.ConversionService} 型別轉換器(Spring 3+,替換了之前的 TypeConverter)
*/
BeanWrapper instanceWrapper = null;
// <1.1> 如果是單例模式,則先嚐試從 `factoryBeanInstanceCache` 快取中獲取例項物件,並從快取中移除
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// <1.2> 使用合適的例項化策略來建立 Bean 的例項:工廠方法、建構函式自動注入、簡單初始化
// 主要是將 BeanDefinition 轉換為 BeanWrapper 物件
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// <1.3> 獲取包裝的例項物件 `bean`
final Object bean = instanceWrapper.getWrappedInstance();
// <1.4> 獲取包裝的例項物件的型別 `beanType`
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
Bean 的例項化階段,會將 Bean 的例項物件封裝成 BeanWrapperImpl 包裝物件,BeanWrapperImpl 承擔的角色:
- Bean 例項的包裝
- PropertyAccessor 屬性編輯器
- PropertyEditorRegistry 屬性編輯器登錄檔
- ConversionService 型別轉換器(Spring 3+,替換了之前的 TypeConverter)
該過程大致如下
- 如果是單例模式,則先嚐試從
factoryBeanInstanceCache
快取中獲取例項物件,並從快取中移除 - 使用合適的例項化策略來建立 Bean 的例項:工廠方法、建構函式自動注入、簡單初始化,主要是將 BeanDefinition 轉換為 BeanWrapper 物件,呼叫
createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
方法 - 獲取包裝的例項物件
bean
- 獲取包裝的例項物件的型別
beanType
createBeanInstance 方法
createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
方法,建立一個 Bean 的例項物件,如下:
// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// <1> 獲取 `beanName` 對應的 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());
}
// <2> 如果存在 Supplier 例項化回撥介面,則使用給定的回撥方法建立一個例項物件
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// <3> 如果配置了 `factory-method` 工廠方法,則呼叫該方法來建立一個例項物件
// 通過 @Bean 標註的方法會通過這裡進行建立
if (mbd.getFactoryMethodName() != null) {
// 這個過程非常複雜,你可以理解為:
// 找到最匹配的 Method 工廠方法,獲取相關引數(依賴注入),然後通過呼叫該方法返回一個例項物件(反射機制)
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
// <4> 判斷這個 RootBeanDefinition 的構造方法是否已經被解析出來了
// 因為找到最匹配的構造方法比較繁瑣,找到後會設定到 RootBeanDefinition 中,避免重複這個過程
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) { // 加鎖
// <4.1> 構造方法已經解析出來了
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
// <4.2> 這個構造方法有入參,表示需要先獲取到對應的入參(構造器注入)
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
// <5> 如果最匹配的構造方法已解析出來
if (resolved) {
// <5.1> 如果這個構造方法有入參
if (autowireNecessary) {
// 這個過程很複雜,你可以理解為:
// 找到最匹配的構造方法,這裡會拿到已經被解析出來的這個方法,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制)
return autowireConstructor(beanName, mbd, null, null);
}
// <5.2> 否則,沒有入參
else {
// 直接呼叫解析出來構造方法,返回一個例項物件(反射機制)
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
// <6> 如果最匹配的構造方法還沒開始解析,那麼需要找到一個最匹配的構造方法,然後建立一個例項物件
/**
* <6.1> 嘗試通過 SmartInstantiationAwareBeanPostProcessor 處理器的 determineCandidateConstructors 方法來找到一些合適的構造方法
* 參考 {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors}
*/
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// <6.2> 是否滿足下面其中一個條件
if (ctors != null // 上一步找到了合適的構造方法
|| mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR // 構造器注入
|| mbd.hasConstructorArgumentValues() // 定義了構造方法的入參
|| !ObjectUtils.isEmpty(args)) // 當前方法指定了入參
{
// 找到最匹配的構造方法,如果 `ctors` 不為空,會從這裡面找一個最匹配的,
// 並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制)
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
/**
* <7> 如果第 `6` 步還不滿足,那麼嘗試獲取優先的構造方法
* 參考 {@link org.springframework.context.support.GenericApplicationContext.ClassDerivedBeanDefinition}
*/
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 如果存在優先的構造方法,則從裡面找到最匹配的一個,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制)
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
// <8> 如果上面多種情況都不滿足,那隻能使用兜底方法了,直接呼叫預設構造方法返回一個例項物件(反射機制)
return instantiateBean(beanName, mbd);
}
過程大致如下:
-
獲取
beanName
對應的 Class 物件 -
如果存在 Supplier 例項化回撥介面,則使用給定的回撥方法建立一個例項物件
-
如果配置了
factory-method
工廠方法,則呼叫該方法來建立一個例項物件,通過 @Bean 標註的方法會通過這裡進行建立
如果上面兩種情況都不是,那麼就進行接下來正常建立 Bean 例項的一個過程
-
判斷這個 RootBeanDefinition 的構造方法是否已經被解析出來了,因為找到最匹配的構造方法比較繁瑣,找到後會設定到 RootBeanDefinition 中,避免重複這個過程
- RootBeanDefinition 的
resolvedConstructorOrFactoryMethod
是否不為空,不為空表示構造方法已經解析出來了 - 構造方法已經解析出來了,則判斷它的
constructorArgumentsResolved
是否不為空,不為空表示有入參,需要先獲取到對應的入參(構造器注入)
- RootBeanDefinition 的
-
如果最匹配的構造方法已解析出來
- 如果這個構造方法有入參,則找到最匹配的構造方法,這裡會拿到已經被解析出來的這個方法,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制)
- 否則,沒有入參,直接呼叫解析出來構造方法,返回一個例項物件(反射機制)
-
如果最匹配的構造方法還沒開始解析,那麼需要找到一個最匹配的構造方法,然後建立一個例項物件
-
先嚐試通過 SmartInstantiationAwareBeanPostProcessor 處理器找到一些合適的構造方法,儲存在
ctors
中 -
是否滿足下面其中一個條件:
ctors
不為空、構造器注入模式、定義了構造方法的入參、當前方法指定了入參,則找到最匹配的構造方法,如果
ctors
不為空,會從這裡面找一個最匹配的,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制)
-
-
如果第
6
步還不滿足,那麼嘗試從 RootBeanDefinition 中獲取優先的構造方法- 如果存在優先的構造方法,則從裡面找到最匹配的一個,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制)
-
如果上面多種情況都不滿足,那隻能使用兜底方法了,直接呼叫預設構造方法返回一個例項物件(反射機制)
整個的例項化過程非常的複雜,接下來進行概括:
-
先拿到對應 Class 物件
-
如果設定了 Supplier 例項化回撥介面,則通過該回撥介面獲取例項物件
-
如果配置了通過
factory-method
工廠方法獲取例項物件,則通過這個方法建立例項物件,@Bean 標註的方法也是通過這裡建立例項物件,方法入參會依賴注入 -
找到最匹配的一個構造方法,並找到對應的入參(構造器注入),通過呼叫該方法返回一個例項物件
-
兜底方法,呼叫預設構造方法建立一個例項物件
因為整個過程比較繁瑣,涉及到的方法行數比較多,所以另起一篇《Bean 的例項化階段》文章進行分析
5. 對 RootBeanDefinition 加工處理
對應程式碼段:
// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Allow post-processors to modify the merged bean definition.
// <2> 對 RootBeanDefinition(合併後)進行加工處理
synchronized (mbd.postProcessingLock) { // 加鎖,執行緒安全
// <2.1> 如果該 RootBeanDefinition 沒有處理過,則進行下面的處理
if (!mbd.postProcessed) {
try {
/**
* <2.2> 對 RootBeanDefinition(合併後)進行加工處理
* 呼叫所有 {@link MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition}
* 【重要】例如有下面兩個處理器:
* 1. AutowiredAnnotationBeanPostProcessor 會先解析出 @Autowired 和 @Value 註解標註的屬性的注入元資訊,後續進行依賴注入;
* 2. CommonAnnotationBeanPostProcessor 會先解析出 @Resource 註解標註的屬性的注入元資訊,後續進行依賴注入,
* 它也會找到 @PostConstruct 和 @PreDestroy 註解標註的方法,並構建一個 LifecycleMetadata 物件,用於後續生命週期中的初始化和銷燬
*/
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
// <2.3> 設定該 RootBeanDefinition 被處理過,避免重複處理
mbd.postProcessed = true;
}
}
在建立好例項物件後,允許你通過 MergedBeanDefinitionPostProcessor 處理器對該 RootBeanDefinition 進行加工處理,也可以從中獲取相關資訊
-
如果該 RootBeanDefinition 沒有加工處理過,則進行下面的處理,否則忽略該過程
-
對 RootBeanDefinition(合併後)進行加工處理,呼叫
applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName)
方法,如下:// AbstractAutowireCapableBeanFactory.java protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof MergedBeanDefinitionPostProcessor) { MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp; bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName); } } }
呼叫所有 MergedBeanDefinitionPostProcessor 的 postProcessMergedBeanDefinition 方法對 RootBeanDefinition 進行加工處理,例如:AutowiredAnnotationBeanPostProcessor 會先解析出
@Autowired
和@Value
註解標註的屬性的注入元資訊,後續進行依賴注入;CommonAnnotationBeanPostProcessor 會先解析出@Resource
註解標註的屬性的注入元資訊,後續進行依賴注入,它也會找到@PostConstruct
和@PreDestroy
註解標註的方法,並構建一個 LifecycleMetadata 物件,用於後續生命週期中的初始化和銷燬 -
設定該 RootBeanDefinition 被處理過,避免重複處理
這個過程在後續講通過 @Autowired 依賴注入的實現原理會被提到
6. 提前暴露當前 Bean
對應程式碼段:
// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// <3> 提前暴露這個 `bean`,如果可以的話,目的是解決單例模式 Bean 的迴圈依賴注入
// <3.1> 判斷是否可以提前暴露
boolean earlySingletonExposure = (mbd.isSingleton() // 單例模式
&& this.allowCircularReferences // 允許迴圈依賴,預設為 true
&& isSingletonCurrentlyInCreation(beanName)); // 當前單例 bean 正在被建立,在前面已經標記過
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
/**
* <3.2>
* 建立一個 ObjectFactory 實現類,用於返回當前正在被建立的 `bean`,提前暴露,儲存在 `singletonFactories` (**三級 Map**)快取中
*
* 可以回到前面的 {@link AbstractBeanFactory#doGetBean#getSingleton(String)} 方法
* 載入 Bean 的過程會先從快取中獲取單例 Bean,可以避免單例模式 Bean 迴圈依賴注入的問題
*/
addSingletonFactory(beanName,
// ObjectFactory 實現類
() -> getEarlyBeanReference(beanName, mbd, bean));
}
在建立好例項物件後,此時還沒有進行屬性的填充和初始化等工作,先判斷是否可以提前暴露這個例項物件,目的是解決單例模式 Bean 的迴圈依賴注入
-
判斷是否可以提前暴露,滿足這些條件:單例模式、允許迴圈依賴(預設為 true)、當前單例 Bean 正在被建立(前面已經標記過)
-
如果可以的話,先通過 Lambda 表示式建立一個 ObjectFactory 實現類,如下:
// AbstractAutowireCapableBeanFactory.java protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; if (!mbd.isSynthetic() // RootBeanDefinition 不是使用者定義的(由 Spring 解析出來的) && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); } } } return exposedObject; }
入參
bean
為當前 Bean 的例項物件(未初始化),這個實現類允許通過 SmartInstantiationAwareBeanPostProcessor 對這個提前暴露的物件進行處理,最終會返回這個提前暴露的物件 -
然後呼叫
addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
方法,如下:// DefaultSingletonBeanRegistry.java protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }
可以看到會往
singletonFactories
集合(三級 Map)中新增當前beanName
和singletonFactory
(ObjectFactory 實現類)的對映關係;從
earlySingletonObjects
集合(二級 Map)中移除當前beanName
;往
registeredSingletons
集合(已註冊的 Bean 的名稱集合)中新增當前beanName
可以回到《開啟 Bean 的載入》文章中2. 從快取中獲取單例 Bean小節,當這個 Bean 出現迴圈依賴注入了,是不是可以避免相關問題,因為可以通過這個 ObjectFactory 實現類獲取到提前暴露的物件
因為迴圈依賴注入的處理貫穿整個 Bean 的載入過程,所以另起一篇《單例 Bean 的迴圈依賴處理》文章進行分析
7. 屬性填充
對應程式碼段:
// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Initialize the bean instance.
// 開始初始化 `bean`
Object exposedObject = bean;
try {
// <4> 對 `bean` 進行屬性填充,注入對應的屬性值
populateBean(beanName, mbd, instanceWrapper);
// <5> 初始化這個 `exposedObject`,呼叫其初始化方法
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);
}
}
在建立好例項物件後,這個物件的屬性還沒有賦值,所以將這個例項物件的相關屬性進行賦值,也就是上面的第 <4>
步
populateBean 方法
populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
方法,屬性填充,如下:
// AbstractAutowireCapableBeanFactory.java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// <1> 如果例項物件為空,則進行下面的判斷
if (bw == null) {
// <1.1> 這個 Bean 有屬性,則丟擲異常
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
// <1.2> 否則,不用屬性填充,直接 `return`
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
// <2> 例項化階段的後置處理,如果滿足這兩個條件
if (!mbd.isSynthetic() // RootBeanDefinition 不是使用者定義的(由 Spring 解析出來的)
&& hasInstantiationAwareBeanPostProcessors()) { // 是否有 InstantiationAwareBeanPostProcessor 處理器
// <2.1> 遍歷所有的 BeanPostProcessor
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 如果為 InstantiationAwareBeanPostProcessor 型別
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// <2.2> 對例項化物件進行後置處理
// 注意如果返回 false,直接 `return`,不會呼叫後面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
// <3> 獲取 `pvs`,承載當前物件的屬性值
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// <4> 獲取這個 Bean 的注入模式,預設為 **AUTOWIRE_NO**,例如可以通過 `@Bean` 註解的 `autowire` 屬性配置注入模式
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// <4.1> 如果注入模式為 **AUTOWIRE_BY_NAME** 或者 **AUTOWIRE_BY_TYPE**,則通過下面的方式獲取屬性值
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// <4.2> 將 `pvs` 封裝成 MutablePropertyValues 物件 `newPvs`(允許對屬性進行相關操作)
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// <4.3> **AUTOWIRE_BY_NAME** 模式,通過名稱獲取相關屬性值,儲存在 `newPvs` 中
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// <4.4> **AUTOWIRE_BY_TYPE** 模式,通過型別獲取相關屬性值,儲存在 `newPvs` 中
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
// <4.5> 將 `newPvs` 複製給 `pvs`
pvs = newPvs;
}
// 是否有 InstantiationAwareBeanPostProcessor 處理器
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否需要進行依賴檢查,預設為 true
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
// <5> 通過 InstantiationAwareBeanPostProcessor 處理器(如果有)對 `pvs` 進行處理
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// <5.1> 遍歷所有的 BeanPostProcessor
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 如果為 InstantiationAwareBeanPostProcessor 型別
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
/**
* Spring 內部的 InstantiationAwareBeanPostProcessor 處理器:
* {@link AutowiredAnnotationBeanPostProcessor#postProcessProperties} 會解析 @Autowired 和 @Value 註解標註的屬性,獲取對應屬性值;
* {@link org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessProperties} 會 解析 Resource 註解標註的屬性,獲取對應的屬性值
*/
// <5.2> 呼叫處理器的 `postProcessProperties(...)` 方法,對 `pvs` 進行後置處理
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// <5.3> 如果上一步的處理結果為空,可能是新版本導致的(Spring 5.1 之前沒有上面這個方法),則需要相容老版本
if (pvsToUse == null) {
// <5.3.1> 找到這個 Bean 的所有 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有資訊)
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// <5.3.2> 呼叫處理器的 `postProcessPropertyValues(...)` 方法,對 `pvs` 進行後置處理
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
// <5.3.3> 如果處理後的 PropertyValues 物件為空,直接 `return`,則不會呼叫後面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充
if (pvsToUse == null) {
return;
}
}
// <5.4> 將處理後的 `pvsToUse` 複製給 `pvs`
pvs = pvsToUse;
}
}
}
// <6> 依賴檢查
if (needsDepCheck) {
// <6.1> 找到這個 Bean 的所有 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有資訊)
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// <6.2> 依賴檢查,如果沒有找到對應的屬性值,則根據檢查策略進行丟擲異常(預設不會)
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// <7> 如果 `pvs` 不為空,則將裡面的屬性值設定到當前 Bean 對應的屬性中(依賴注入)
// 前面找到的屬性值並沒有設定到 Bean 中,且屬性值可能是一個表示式,型別也可能也不對,需要先進行處理和型別轉換,然後再設定到該例項物件中
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
過程大致如下:
-
如果例項物件為
null
,則進行下面的判斷- 這個 Bean 有屬性,則丟擲異常
- 否則,不用屬性填充,直接
return
-
例項化階段的後置處理,如果滿足這兩個條件:RootBeanDefinition 不是使用者定義的(由 Spring 解析出來的)、是否有 InstantiationAwareBeanPostProcessor 處理器
-
遍歷所有的 BeanPostProcessor
-
如果為 InstantiationAwareBeanPostProcessor 型別,則對例項化物件進行後置處理
注意,如果返回 false,直接
return
,不會呼叫後面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充
-
-
獲取
pvs
,承載當前物件的屬性值 -
獲取這個 Bean 的注入模式,預設為 AUTOWIRE_NO,例如可以通過
@Bean
註解的autowire
屬性配置注入模式- 如果注入模式為 AUTOWIRE_BY_NAME 或者 AUTOWIRE_BY_TYPE,則通過下面的方式獲取屬性值
- 將
pvs
封裝成 MutablePropertyValues 物件newPvs
(允許對屬性進行相關操作) - AUTOWIRE_BY_NAME 模式,通過名稱獲取相關屬性值,儲存在
newPvs
中,呼叫autowireByName(...)
方法 - AUTOWIRE_BY_TYPE 模式,通過型別獲取相關屬性值,儲存在
newPvs
中,呼叫autowireByType(...)
方法 - 將
newPvs
複製給pvs
-
通過 InstantiationAwareBeanPostProcessor 處理器(如果有)對
pvs
進行處理- 遍歷所有的 BeanPostProcessor
- 如果為 InstantiationAwareBeanPostProcessor 型別,則呼叫其
postProcessProperties(...)
方法,對pvs
進行後置處理 - 如果上一步的處理結果為空,可能是新版本導致的(Spring 5.1 之前沒有上面這個方法),則需要相容老版本
- 嘗試找到這個 Bean 的所有
java.beans.PropertyDescriptor
屬性描述器(包含這個屬性的所有資訊) - 呼叫處理器的
postProcessPropertyValues(...)
方法,對pvs
進行後置處理 - 如果處理後的 PropertyValues 物件為空,直接
return
,則不會呼叫後面的處理器,也不會進行接下來的屬性填充
- 嘗試找到這個 Bean 的所有
- 將處理後的
pvsToUse
複製給pvs
-
依賴檢查
- 找到這個 Bean 的所有
java.beans.PropertyDescriptor
屬性描述器(包含這個屬性的所有資訊) - 進行依賴檢查,如果沒有找到對應的屬性值,則根據檢查策略進行丟擲異常(預設不會)
- 找到這個 Bean 的所有
-
如果
pvs
不為空,則將裡面的屬性值設定到當前 Bean 對應的屬性中(依賴注入),呼叫applyPropertyValues(...)
方法前面找到的屬性值並沒有設定到 Bean 中,且屬性值可能是一個表示式,型別也可能也不對,需要先進行處理和型別轉換,然後再設定到該例項物件中
整個的屬性填充過程非常的複雜,接下來進行概括:
- 允許你對例項化物件進行後置處理,處理結果為
false
表示不需要進行接下來的屬性填充過程 - 根據注入模式,找到沒有配置屬性值的物件屬性,然後找到對應的 Bean,預設注入模式為不注入
- 允許你對屬性值進行後置處理,例如
@Autowired
、@Value
等註解標註的屬性會通過這裡找到對應的屬性值(或物件) - 上述過程僅找到了屬性值,還沒設定到當前例項物件中,所以最後一步才是真正的屬性填充
因為整個過程比較繁瑣,涉及到的方法行數比較多,所以另起一篇《Bean 的屬性填充階段》文章進行分析
8. 初始化 Bean
對應程式碼段:
// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Initialize the bean instance.
// 開始初始化 `bean`
Object exposedObject = bean;
try {
// <4> 對 `bean` 進行屬性填充,注入對應的屬性值
populateBean(beanName, mbd, instanceWrapper);
// <5> 初始化這個 `exposedObject`,呼叫其初始化方法
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);
}
}
例項物件已經有了,且相關屬性已經填充了,那麼接下來需要進行相關初始化工作,也就是上面的第 <5>
步
initializeBean
// AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) { // 安全模式
// <1> Aware 介面的回撥
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// <1> Aware 介面的回撥
invokeAwareMethods(beanName, bean);
}
/**
* <2> **初始化**階段的**前置處理**,執行所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法
*
* 在 {@link AbstractApplicationContext#prepareBeanFactory} 方法中會新增 {@link ApplicationContextAwareProcessor} 處理器
* 用於處理其他 Aware 介面的回撥,例如ApplicationContextAware、EnvironmentAware、ApplicationEventPublisherAware
*
* 在 {@link AnnotationConfigUtils#registerAnnotationConfigProcessors} 方法中會註冊 {@link CommonAnnotationBeanPostProcessor} 處理器
* 在這裡會執行 @PostConstruct 註解標註的方法
*/
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// <3> 啟用自定義的初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
/**
* <4> **初始化**階段的**後置處理**,執行所有 BeanPostProcessor 的 postProcessAfterInitialization 方法
*
* 在 {@link AbstractApplicationContext#prepareBeanFactory} 方法中會新增 {@link ApplicationListenerDetector} 處理器
* 如果是單例 Bean 且為 ApplicationListener 型別,則新增到 Spring 應用上下文,和 Spring 事件相關
*/
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
初始化過程如下:
-
Aware 介面的回撥,呼叫
invokeAwareMethods(final String beanName, final Object bean)
方法,如下:// AbstractAutowireCapableBeanFactory.java private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); } } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } }
如果是 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware,則呼叫其
setXxx
方法 -
初始化階段的前置處理,執行所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法,如下:
// AbstractAutowireCapableBeanFactory.java @Override public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; // 遍歷所有 BeanPostProcessor for (BeanPostProcessor processor : getBeanPostProcessors()) { // 初始化的前置處理,返回 `current` 處理結果 Object current = processor.postProcessBeforeInitialization(result, beanName); // 處理結果為空,則直接返回 `result` if (current == null) { return result; } // 否則,`result` 複製 `current` result = current; } return result; }
例如 Spring 內部有下面兩個處理器
ApplicationContextAwareProcessor:ApplicationContextAware、ApplicationEventPublisherAware、EnvironmentAware 等其他 Aware 介面的回撥
CommonAnnotationBeanPostProcessor:
@PostConstruct
註解標註的方法的呼叫 -
啟用自定義的初始化方法,如下:
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { // <1> InitializingBean 介面的回撥(如果是) boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isTraceEnabled()) { logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { // 安全模式 try { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { // 呼叫其 afterPropertiesSet() 方法 ((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { // 呼叫其 afterPropertiesSet() 方法 ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { // <2> 呼叫通過 `init-method` 指定的初始化方法(反射機制) invokeCustomInitMethod(beanName, bean, mbd); } } }
- InitializingBean 介面的回撥(如果是),呼叫其
afterPropertiesSet()
方法 - 呼叫通過
init-method
指定的初始化方法(反射機制)
- InitializingBean 介面的回撥(如果是),呼叫其
-
初始化階段的後置處理,執行所有 BeanPostProcessor 的 postProcessAfterInitialization 方法,如下:
// AbstractAutowireCapableBeanFactory.java @Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; // 遍歷所有 BeanPostProcessor for (BeanPostProcessor processor : getBeanPostProcessors()) { // 初始化的後置處理,返回 `current` 處理結果 Object current = processor.postProcessAfterInitialization(result, beanName); // 處理結果為空,則直接返回 `result` if (current == null) { return result; } // 否則,`result` 複製 `current` result = current; } return result; }
例如 Spring 內部有一個 ApplicationListenerDetector 處理器,如果是單例 Bean 且為 ApplicationListener 型別,則新增到 Spring 應用上下文,和 Spring 事件相關
整個的初始化過程並不複雜,其中也有對應的擴充套件點,初始化前置處理和後置處理,總的概括如下:
-
Aware
介面的回撥 -
JSR-250
@PostConstruct
標註的方法的呼叫 -
InitializingBean#afterPropertiesSet
方法的回撥 -
init-method
初始化方法的呼叫
9. 迴圈依賴注入的檢查
對應程式碼段:
// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// <6> 迴圈依賴注入的檢查
if (earlySingletonExposure) {
// <6.1> 獲取當前正在建立的 `beanName` 被依賴注入的早期引用
// 注意,這裡有一個入參是 `false`,不會呼叫上面第 `3` 步的 ObjectFactory 實現類
// 也就是說當前 `bean` 如果出現迴圈依賴注入,這裡才能獲取到提前暴露的引用
Object earlySingletonReference = getSingleton(beanName, false);
// <6.2> 如果出現了迴圈依賴注入,則進行接下來的檢查工作
if (earlySingletonReference != null) {
// <6.2.1> 如果 `exposedObject` 沒有在初始化階段中被改變,也就是沒有被增強
// 則使用提前暴露的那個引用
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// <6.2.2> 否則,`exposedObject` 已經不是被別的 Bean 依賴注入的那個 Bean
else if (!this.allowRawInjectionDespiteWrapping // 是否允許注入未加工的 Bean,預設為 false,這裡取非就為 true
&& hasDependentBean(beanName)) { // 存在依賴 `beanName` 的 Bean(通過 `depends-on` 配置)
// 獲取依賴當前 `beanName` 的 Bean 們的名稱(通過 `depends-on` 配置)
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
// 接下來進行判斷,如果依賴 `beanName` 的 Bean 已經建立
// 說明當前 `beanName` 被注入了,而這裡最終的 `bean` 被包裝過,不是之前被注入的
// 則丟擲異常
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.");
}
}
}
}
在前面 6. 提前暴露當前 Bean 小節中,如果提前暴露了 Bean,則可能存在迴圈依賴注入,這裡需要進行一些檢查,過程大致如下:
-
獲取當前正在建立的
beanName
被依賴注入的早期引用,這裡呼叫方法也就是從快取中獲取單例 Bean 的方法。注意,這裡有一個入參是
false
,不會呼叫前面 6. 提前暴露當前 Bean 小節中快取的 ObjectFactory 實現類,也就是說當前bean
如果出現迴圈依賴注入,這裡才能獲取到提前暴露的引用 -
如果上一步獲取到了提前暴露的引用,也就是出現了迴圈依賴注入,則進行接下來的檢查工作
- 如果
exposedObject
沒有在初始化階段中被改變,也就是沒有被增強,則使用提前暴露的那個引用 - 否則,
exposedObject
已經不是被別的 Bean 依賴注入的那個 Bean,則進行相關判斷
- 如果
當出現迴圈依賴注入,這裡會檢查填充屬性和初始化的過程中是否改變了這個 beanName
,改變了的話需要判斷依賴當前 beanName
的 Bean 們是否已經建立了,如果已經建立了,那麼可能它拿到的 beanName
不是這裡初始化後的物件(被修改了),所以需要丟擲異常
10. 註冊可銷燬的 Bean
對應程式碼段:
// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Register bean as disposable.
try {
/**
* <7> 為當前 `bean` 註冊 DisposableBeanAdapter(如果需要的話),用於 Bean 生命週期中的銷燬階段
* 可以看到 {@link DefaultSingletonBeanRegistry#destroySingletons()} 方法
*/
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
這裡會呼叫 registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd)
方法,如下:
// AbstractBeanFactory.java
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() // 不是原型模式
&& requiresDestruction(bean, mbd)) // 有銷燬的必要,也就是定義了銷燬方法
{
if (mbd.isSingleton()) { // 單例模式
// Register a DisposableBean implementation that performs all destruction work for the given bean:
// DestructionAwareBeanPostProcessors, DisposableBean interface, custom destroy method.
// 建立一個 DisposableBeanAdapter 物件封裝這個 Bean,然後儲存在 `disposableBeans` Map 集合中
registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else { // 其他模式
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
// 建立一個 DisposableBeanAdapter 物件封裝這個 Bean,往其他模式的 Scope 物件裡面註冊
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
如果不是原型模式,並且有銷燬的必要,也就是定義了銷燬方法,則需要建立一個 DisposableBeanAdapter 物件封裝這個 Bean,在生命週期的銷燬階段需要先通過這個物件先執行銷燬方法,這個物件如何儲存的:
- 單例模式:儲存在
disposableBeans
Map 集合中 - 其他模式:往 Scope 物件裡面註冊
11. 返回 Bean
經過上面一系列的過程,例項化、屬性填充、初始化等階段,已經建立好了這個 Bean,最後直接返回
總結
當我們顯示或者隱式地呼叫AbstractBeanFactory
的 getBean(...)
方法時,會觸發 Bean 的載入,載入過程在上一篇《開啟 Bean 的載入》文章中已經分析過。對於不同作用域的 Bean,底層都會呼叫 AbstractAutowireCapableBeanFactory
的 createBean(...)
方法進行建立,建立 Bean 的過程如下:
- Class 物件載入階段
- 例項化前階段(如果返回了一個物件則直接返回,不會進行下面的階段)
- 例項化階段
- 例項化後階段
- 提前暴露單例 Bean(迴圈依賴處理的關鍵)
- 屬性填充階段
- Aware 介面回撥階段
- 初始化前階段
- 初始化階段
- 初始化後階段
建立 Bean 的過程非常複雜,在不同的階段都會講到 BeanPostProcessor(及其子類)的身影,Spring 內部很多功能都是基於該處理器介面實現的,當然開發者也可以通過其進行擴充,使得框架變得非常靈活。其中 Bean 的例項化和屬性填充兩個階段比較複雜,這裡沒有深入分析,可參考後續文章。提前暴露單例 Bean 迴圈依賴處理的關鍵,後續文章也會再次分析。
你是否還有疑問,例如我們常用的 @Autowired、@Value、@Resource、@Bean、@Import、@ComponentScan 等註解會在哪被解析呢?
彆著急,後面的文章都會講到,我們先把 Bean 的載入過程搞明白,然後再講 Spring 應用上下文的生命週期