該系列文章是本人在學習 Spring 的過程中總結下來的,裡面涉及到相關原始碼,可能對讀者不太友好,請結合我的原始碼註釋 Spring 原始碼分析 GitHub 地址 進行閱讀
Spring 版本:5.1.14.RELEASE
開始閱讀這一系列文章之前,建議先檢視《深入瞭解 Spring IoC(面試題)》這一篇文章
該系列其他文章請檢視:《死磕 Spring 之 IoC 篇 - 文章導讀》
Bean 的例項化階段
當我們顯示或者隱式地呼叫AbstractBeanFactory
的 getBean(...)
方法時,會觸發 Bean 的載入,在《開啟 Bean 的載入》文章中分析了整個載入過程。
對於不同作用域的 Bean,底層都會呼叫 AbstractAutowireCapableBeanFactory
的 createBean(...)
方法進行建立,在上一篇《Bean 的建立過程》文章中分析了整個建立過程。在建立 Bean 的過程中,需要先獲取其 Class 物件,然後通過構造方法建立一個例項物件(反射機制),再進行後續的屬性填充和初始化工作。整個的例項化過程非常複雜,因為需要找到最匹配的構造方法,還需要找到該方法的入參,所以會有各種處理,本文將會分析建立 Bean 過程中的例項化階段。
回顧
先來回顧一下建立 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
快取(儲存 FactoryBean 型別的物件)中獲取例項物件,並從快取中移除。目前在建立 Bean 的過程中沒發現往這個集合中新增快取,暫時忽略。我們直接看到下面的一步,呼叫 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) {
// <7.1> 如果存在優先的構造方法,則從裡面找到最匹配的一個,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制)
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
// <8> 如果上面多種情況都不滿足,那隻能使用兜底方法了,直接呼叫預設構造方法返回一個例項物件(反射機制)
return instantiateBean(beanName, mbd);
}
過程大致如下:
-
獲取
beanName
對應的 Class 物件 -
如果存在 Supplier 例項化回撥介面,則使用給定的回撥方法建立一個例項物件,呼叫 obtainFromSupplier(...) 方法建立
-
如果配置了
factory-method
工廠方法,則呼叫該方法來建立一個例項物件,通過 @Bean 標註的方法會通過這裡進行建立,呼叫 instantiateUsingFactoryMethod(...) 方法建立
如果上面兩種情況都不是,那麼就進行接下來正常建立 Bean 例項的一個過程
-
判斷這個 RootBeanDefinition 的構造方法是否已經被解析出來了,因為找到最匹配的構造方法比較繁瑣,找到後會設定到 RootBeanDefinition 中,避免重複這個過程
- RootBeanDefinition 的
resolvedConstructorOrFactoryMethod
是否不為空,不為空表示構造方法已經解析出來了 - 構造方法已經解析出來了,則判斷它的
constructorArgumentsResolved
是否不為空,不為空表示有入參,需要先獲取到對應的入參(構造器注入)
- RootBeanDefinition 的
-
如果最匹配的構造方法已解析出來
- 如果這個構造方法有入參,則找到最匹配的構造方法,這裡會拿到已經被解析出來的這個方法,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制),呼叫 autowireConstructor(...) 方法建立
- 否則,沒有入參,直接呼叫解析出來構造方法,返回一個例項物件(反射機制),呼叫 instantiateBean(...) 方法建立
-
如果最匹配的構造方法還沒開始解析,那麼需要找到一個最匹配的構造方法,然後建立一個例項物件
-
先嚐試通過 SmartInstantiationAwareBeanPostProcessor 處理器找到一些合適的構造方法,儲存在
ctors
中 -
是否滿足下面其中一個條件:
ctors
不為空、構造器注入模式、定義了構造方法的入參、當前方法指定了入參,則找到最匹配的構造方法,如果
ctors
不為空,會從這裡面找一個最匹配的,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制),呼叫 autowireConstructor(...) 方法建立
-
-
如果第
6
步還不滿足,那麼嘗試從 RootBeanDefinition 中獲取優先的構造方法- 如果存在優先的構造方法,則從裡面找到最匹配的一個,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制),呼叫 autowireConstructor(...) 方法建立
-
如果上面多種情況都不滿足,那隻能使用兜底方法了,直接呼叫預設構造方法返回一個例項物件(反射機制),呼叫 instantiateBean(...) 方法建立
整個的例項化過程非常的複雜,主要分為以下幾種情況:
- 指定了 Supplier 例項化回撥介面,則回撥該介面,返回一個例項物件
- 配置了
factory-method
工廠方法建立當前 Bean,則找到這個方法,然後建立一個例項物件(@Bean 註解底層原理也是這種方式) - 找到一個最匹配的構造方法,返回一個例項物件,這個構造方法會設定到這個 RootBeanDefinition 中,避免再次解析,提高效能
- 兜底方法,使用預設構造方法返回一個例項物件
這四種情況,其實就分別對應上面四個加粗的方法,接下來依次分析這四個方法
obtainFromSupplier 方法
obtainFromSupplier(Supplier<?> instanceSupplier, String beanName)
方法,通過 Supplier 回撥介面獲取一個例項物件,方法如下:
// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
Object instance;
// 獲得原當前執行緒正在建立的 Bean 的名稱
String outerBean = this.currentlyCreatedBean.get();
// 設定當前執行緒正在建立的 Bean 的名稱
this.currentlyCreatedBean.set(beanName);
try {
// <1> 呼叫 Supplier 的 get(),返回一個例項物件
instance = instanceSupplier.get();
}
finally {
if (outerBean != null) {
// 設定原當前執行緒正在建立的 Bean 的名稱到當前執行緒變數中
this.currentlyCreatedBean.set(outerBean);
}
else {
this.currentlyCreatedBean.remove();
}
}
// 未建立 Bean 物件,則建立 NullBean 空物件
if (instance == null) {
instance = new NullBean();
}
// <2> 將例項物件封裝成 BeanWrapper 物件
BeanWrapper bw = new BeanWrapperImpl(instance);
// <3> 初始化這個 BeanWrapper 物件
initBeanWrapper(bw);
return bw;
}
過程如下:
- 呼叫 Supplier 介面的
get()
,返回instance
例項物件 - 將
instance
封裝成 BeanWrapper 物件bw
- 對
bw
進行初始化,設定 ConversionService 型別轉換器,並註冊自定義的屬性編輯器
整個過程比較簡單
instantiateUsingFactoryMethod 方法
通過 factoryMethodName
工廠方法建立一個例項物件,例如 XML 配置的 factory-method
屬性或者 @Bean
標註的方法都會解析成 factoryMethodName
屬性
這個過程非常複雜,你可以理解為去找到最匹配的 Method 工廠方法,獲取相關入參(依賴注入),然後呼叫該方法返回一個例項物件(反射機制),方法如下:
// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
建立 ConstructorResolver 物件,然後呼叫其 instantiateUsingFactoryMethod(...)
方法,如下:
// ConstructorResolver.java
public BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
// 構造 BeanWrapperImpl 物件
BeanWrapperImpl bw = new BeanWrapperImpl();
// 初始化 BeanWrapperImpl,設定 ConversionService 型別轉換器,並註冊自定義的屬性編輯器
this.beanFactory.initBeanWrapper(bw);
// -------------------------獲取工廠方法的相關資訊-------------------------
// <1> 獲取工廠方法的相關資訊
// 工廠方法所在類對應的 Bean(靜態方法不會有)
Object factoryBean;
// 工廠方法所在類的 Class 物件
Class<?> factoryClass;
// 是否為 static 修飾的靜態方法
boolean isStatic;
// 獲取工廠方法所在類對應的 Bean 的名稱(靜態方法不會有)
String factoryBeanName = mbd.getFactoryBeanName();
// <1.1> 非靜態方法
if (factoryBeanName != null) {
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
// 獲取工廠方法所在類對應的 Bean,不然無法呼叫工廠方法
factoryBean = this.beanFactory.getBean(factoryBeanName);
// 如果是單例模式,已經存在對應的 Bean,則丟擲重複建立的異常
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
factoryClass = factoryBean.getClass();
isStatic = false;
}
// <1.2> 靜態方法
else {
// It's a static factory method on the bean class.
// 靜態方法沒有找到對應的 Class 物件無法被呼叫,則丟擲異常
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"bean definition declares neither a bean class nor a factory-bean reference");
}
factoryBean = null;
factoryClass = mbd.getBeanClass();
isStatic = true;
}
// -------------------------嘗試獲取工廠方法物件和入參-------------------------
// <2> 嘗試獲取工廠方法物件和引數
// 工廠方法物件
Method factoryMethodToUse = null;
ArgumentsHolder argsHolderToUse = null;
// 方法引數
Object[] argsToUse = null;
// <2.1> 如果方法入參指定了引數,則直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
// <2.2> 否則,嘗試從 RootBeanDefinition 中獲取已解析出來的工廠方法和入參
else {
Object[] argsToResolve = null;
// 因為可能前面解析了,會臨時快取,避免再次解析
synchronized (mbd.constructorArgumentLock) { // 加鎖
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
// 如果工廠方法被解析了,那麼引數也可能解析過
if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached factory method...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 沒有解析過的引數,則嘗試從 RootBeanDefinition 中獲取未被解析過的引數
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果獲取到了未被解析過的入參,則進行解析
if (argsToResolve != null) {
// 處理引數值,型別轉換,例如給定方法 A(int, int),配置了 A("1"、"2") 兩個引數,則會轉換為 A(1, 1)
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
}
}
// -------------------------找到所有匹配的工廠方法-------------------------
// <3> 如果上一步沒有找到工廠方法物件或方法入參集合,則需要進行接下來的解析過程,首先找到所有匹配的工廠方法
if (factoryMethodToUse == null || argsToUse == null) {
// Need to determine the factory method...
// Try all methods with this name to see if they match the given arguments.
// <3.1> 獲取工廠方法所在的類的例項 Class 物件,因為可能是 Cglib 提升過的子類
factoryClass = ClassUtils.getUserClass(factoryClass);
// <3.2> 獲取工廠方法所在的類中所有方法物件
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
// <3.3> 找到這個類中匹配的工廠方法
List<Method> candidateList = new ArrayList<>();
for (Method candidate : rawCandidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic // 是否和 `isStatic` 匹配
&& mbd.isFactoryMethod(candidate)) { // 和定義的工廠方法的名稱是否相等
candidateList.add(candidate);
}
}
// <3.4> 如果只有一個匹配的方法,且這個方法沒有給指定的入參,且本身也沒有定義引數,且這個方法沒有定義入參
// 則直接呼叫這個方法建立一個例項物件(反射機制),並返回
if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Method uniqueCandidate = candidateList.get(0);
if (uniqueCandidate.getParameterCount() == 0) {
mbd.factoryMethodToIntrospect = uniqueCandidate;
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
mbd.constructorArgumentsResolved = true;
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
// -------------------------開始找最匹配的工廠方法-------------------------
// <4> 開始找最匹配的工廠方法
// 將匹配的工廠方法轉換成陣列
Method[] candidates = candidateList.toArray(new Method[0]);
// 將匹配的方法進行排序,public 方法優先,入參個數多的優先
AutowireUtils.sortFactoryMethods(candidates);
// 用於承載解析後的方法引數值
ConstructorArgumentValues resolvedValues = null;
// 是否是構造器注入
boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
int minTypeDiffWeight = Integer.MAX_VALUE;
// 匹配方法的集合
Set<Method> ambiguousFactoryMethods = null;
// -------------------------確定方法引數的入引數量-------------------------
// <5> 確定方法引數的入引數量,匹配的方法的入引數量要多餘它
// 方法的引數數量的最小值
int minNrOfArgs;
// <5.1> 如果當前方法指定了入參,則使用其個數作為最小值
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
// <5.1> 否則,從 RootBeanDefinition 解析出方法的引數個數作為最小值
else {
// We don't have arguments passed in programmatically, so we need to resolve the
// arguments specified in the constructor arguments held in the bean definition.
// RootBeanDefinition 定義了引數值
if (mbd.hasConstructorArgumentValues()) {
// 方法的引數
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
// 解析定義的引數值,放入 `resolvedValues` 中,並返回引數個數
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
else {
minNrOfArgs = 0;
}
}
// 記錄 UnsatisfiedDependencyException 異常的集合
LinkedList<UnsatisfiedDependencyException> causes = null;
// 遍歷匹配的方法
for (Method candidate : candidates) {
// 方法體的引數
Class<?>[] paramTypes = candidate.getParameterTypes();
if (paramTypes.length >= minNrOfArgs) {
// -------------------------解析出工廠方法的入參-------------------------
// <6> 解析出工廠方法的入參
// 儲存引數的物件
ArgumentsHolder argsHolder;
// <6.1> 如果當前方法指定了入參,則直接使用
if (explicitArgs != null) {
// Explicit arguments given -> arguments length must match exactly.
// 顯示給定引數,引數長度必須完全匹配
if (paramTypes.length != explicitArgs.length) {
continue;
}
// 根據引數建立引數持有者 ArgumentsHolder 物件
argsHolder = new ArgumentsHolder(explicitArgs);
}
// <6.2> 否則,通過**依賴注入**獲取入參
else {
// Resolved constructor arguments: type conversion and/or autowiring necessary.
// 為提供引數,解析構造引數
try {
String[] paramNames = null;
// 獲取 ParameterNameDiscoverer 引數名稱探測器
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
// 獲取方法的引數名稱
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
// 解析出方法的入參,引數值會被依賴注入
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
// 若發生 UnsatisfiedDependencyException 異常,新增到 causes 中。
if (logger.isTraceEnabled()) {
logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next overloaded factory method.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
// -------------------------根據權重獲取最匹配的方法-------------------------
// <7> 因為會遍歷所有匹配的方法,所以需要進行權重的判斷,拿到最優先的那個
// 判斷解析建構函式的時候是否以寬鬆模式還是嚴格模式,預設為 true
// 嚴格模式:解析建構函式時,必須所有的都需要匹配,否則丟擲異常
// 寬鬆模式:使用具有"最接近的模式"進行匹配
// typeDiffWeight:型別差異權重
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this factory method if it represents the closest match.
// 代表最匹配的結果,則選擇作為符合條件的方法
if (typeDiffWeight < minTypeDiffWeight) {
factoryMethodToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousFactoryMethods = null;
}
// Find out about ambiguity: In case of the same type difference weight
// for methods with the same number of parameters, collect such candidates
// and eventually raise an ambiguity exception.
// However, only perform that check in non-lenient constructor resolution mode,
// and explicitly ignore overridden methods (with the same parameter signature).
// 如果具有相同引數數量的方法具有相同的型別差異權重,則收集此型別選項
// 但是,僅在非寬鬆建構函式解析模式下執行該檢查,並顯式忽略重寫方法(具有相同的引數簽名)
else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
!mbd.isLenientConstructorResolution() &&
paramTypes.length == factoryMethodToUse.getParameterCount() &&
!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
// 查詢到多個可匹配的方法
if (ambiguousFactoryMethods == null) {
ambiguousFactoryMethods = new LinkedHashSet<>();
ambiguousFactoryMethods.add(factoryMethodToUse);
}
ambiguousFactoryMethods.add(candidate);
}
}
}
// <8> 沒有找到對應的工廠方法,則丟擲異常
if (factoryMethodToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
List<String> argTypes = new ArrayList<>(minNrOfArgs);
if (explicitArgs != null) {
for (Object arg : explicitArgs) {
argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
}
}
else if (resolvedValues != null) {
Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
valueHolders.addAll(resolvedValues.getGenericArgumentValues());
for (ValueHolder value : valueHolders) {
String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
argTypes.add(argType);
}
}
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"No matching factory method found: " +
(mbd.getFactoryBeanName() != null ?
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
"Check that a method with the specified name " +
(minNrOfArgs > 0 ? "and arguments " : "") +
"exists and that it is " +
(isStatic ? "static" : "non-static") + ".");
}
else if (void.class == factoryMethodToUse.getReturnType()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Invalid factory method '" + mbd.getFactoryMethodName() +
"': needs to have a non-void return type!");
}
else if (ambiguousFactoryMethods != null) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous factory method matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousFactoryMethods);
}
// <9> 將解析出來的工廠方法和入參快取,設定到 RootBeanDefinition 中,因為整個過程比較複雜,避免再次解析
if (explicitArgs == null && argsHolderToUse != null) {
mbd.factoryMethodToIntrospect = factoryMethodToUse;
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
}
Assert.state(argsToUse != null, "Unresolved factory method arguments");
// <10> 呼叫工廠方法建立一個例項物件(反射機制),並設定到 `bw` 中
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
return bw;
}
這個方法我真的是吐了?,也太長了吧,硬著頭皮看完了一部分,參考檔案:ConstructorResolver.java
對於過程不感興趣的可以跳過直接看下面的概括,過程大致如下:
先建立一個 BeanWrapperImpl 物件 bw
,並初始化,設定 ConversionService 型別轉換器,並註冊自定義的屬性編輯器
- 獲取工廠方法的相關資訊,根據 RootBeanDefinition 的
factoryBeanName
屬性判斷是否為靜態方法,這個屬性表示這個工廠方法所在類對應 Bean 的名稱,當然靜態方法“不屬於”這個 Bean,所以它的這個屬性為空factoryBeanName
屬性不為空,表示不是靜態方法,則需要根據factoryBeanName
找到(依賴查詢)對應的 Bean,作為factoryBean
- 否則,就是靜態方法,獲取所在類的 Class 物件即可
這一步找到了三個物件:factoryBean
(工廠方法所在類對應的 Bean,靜態方法不會有)、factoryClass
(工廠方法所在類的 Class 物件)、isStatic
(是否為靜態方法)。所以想要通過工廠方法獲取一個 Bean,則需要方法所在類對應的 Bean 先初始化,然後才能呼叫這個方法建立 Bean;而靜態方法就不用,因為它可以根據所在類的 Class 物件就能呼叫這個方法建立 Bean,這就是兩者的區別。
-
嘗試獲取工廠方法 Method 物件和入參
-
如果方法入參指定了引數,則直接使用
-
否則,嘗試從 RootBeanDefinition 中獲取已解析出來的工廠方法和入參,如果獲取到了未被解析過的入參,則進行解析(型別轉換)
例如給定方法 A(int, int),配置了 A("1"、"2") 兩個引數,則會轉換為 A(1, 1)
-
這一步嘗試獲取兩個物件:factoryMethodToUse
(對應的工廠方法 Method)、argsToUse
(工廠方法的入參集合)
- 如果上一步沒有找到工廠方法物件或方法入參集合,找到所有匹配的工廠方法,首先找到所有匹配的工廠方法
- 獲取工廠方法所在的類的例項 Class 物件,因為可能是 Cglib 提升過的子類
- 獲取工廠方法所在的類中所有方法物件
- 找到這個類中匹配的工廠方法,是否和
isStatic
匹配,並且和定義的工廠方法的名稱是否相等 - 如果只有一個匹配的方法,且這個方法沒有給指定的入參,且本身也沒有定義引數,且這個方法沒有定義入參,則直接呼叫這個方法建立一個例項物件(反射機制),並返回
上面第 3.3
步找到的通常只有一個,如果沒有入參則可以直接進入第 3.4
步,使用這個方法建立一個例項物件。不過你可能定義了過載方法,也可能定義了方法引數,所以需要進行接下來的解析過程
- 開始找最匹配的工廠方法,先排序,public 方法優先,入參個數多的優先
- 確定方法引數的入引數量,匹配的方法的入引數量要多餘它
- 如果當前方法指定了入參,則使用其個數作為最小值
- 否則,從 RootBeanDefinition 解析出方法的引數個數作為最小值,沒有定義則設定為 0
這一步主要是確定入參的個數,並排序所有匹配的方法,接下來會遍歷所有匹配的方法
- 解析出工廠方法的入參
- 如果當前方法指定了入參,則直接使用
- 否則,通過依賴注入獲取入參
這一步會找到這個方法的入參,依賴注入的方式
- 因為會遍歷所有匹配的方法,所以需要進行權重的判斷,拿到最優先的那個
通常情況下,我們只有一個匹配的方法,如果存在多個,會根據方法的引數型別進行權重
- 沒有找到對應的工廠方法,則丟擲異常
- 將解析出來的工廠方法和入參快取,設定到 RootBeanDefinition 中,因為整個過程比較複雜,避免再次解析
會快取這幾個資料:resolvedConstructorOrFactoryMethod
(已經解析出來的工廠方法)、constructorArgumentsResolved
(方法入參已經解析出來了 true)、resolvedConstructorArguments
(解析出來的入參)
- 呼叫工廠方法建立一個例項物件(反射機制),並設定到
bw
中
上面整個過程非常複雜,這裡進行簡單概括:
-
找到對應的工廠方法,如果是非靜態方法,則需要先依賴查詢到所在類對應的 Bean,因為需要根據這個 Bean 去呼叫對應的工廠方法,而靜態方法不用,可以根據其 Class 物件呼叫對應的工廠方法
-
如果工廠方法有入參,則需要注入相關物件(依賴注入)
-
呼叫這個方法(反射機制),返回一個例項物件
autowireConstructor 方法
這個過程和上一個方法一樣非常複雜,不過差不太多,你可以理解為去找到當前 Bean 的構造方法,獲取相關入參(構造器注入),然後呼叫該構造方法返回一個例項物件(反射機制),方法如下:
// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
建立 ConstructorResolver 物件,然後呼叫其 autowireConstructor(...)
方法,如下:
// ConstructorResolver.java
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
// 構造 BeanWrapperImpl 物件
BeanWrapperImpl bw = new BeanWrapperImpl();
// 初始化 BeanWrapperImpl,設定 ConversionService 型別轉換器,並註冊自定義的屬性編輯器
this.beanFactory.initBeanWrapper(bw);
// -------------------------嘗試獲取構造方法和入參-------------------------
// <1> 嘗試獲取構造方法和入參
// 構造方法
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
// 構造方法的入參集合
Object[] argsToUse = null;
// <1.1> 如果當前方法入參指定了引數,則直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
// <1.2> 否則,嘗試從 RootBeanDefinition 中獲取已解析出來的構造方法和入參
else {
// 因為可能前面解析了,會臨時快取,避免再次解析
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
// 如果構造方法被解析了,那麼引數也可能解析過
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 沒有解析過的引數,則嘗試從 RootBeanDefinition(合併後)中獲取未被解析過的引數
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果獲取到了未被解析過的入參
if (argsToResolve != null) {
// 處理引數值,型別轉換,例如給定方法 A(int, int),配配置了 A("1"、"2") 兩個引數,則會轉換為 A(1, 1)
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
// -------------------------開始獲取構造方法和入參-------------------------
// <2> 如果上一步沒有找到構造方法或入參集合,找到所有匹配的工廠方法,首先找到所有匹配的構造方法
if (constructorToUse == null || argsToUse == null) {
// Take specified constructors, if any.
// <2.1> 獲取所有的構造方法,如果當前方法指定了構造方法的集合,則使用這個集合
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
}
// <2.2> 如果構造方法只有一個,且當前方法的入參沒有指定引數,且本身也沒有定義引數,且這個構造方法沒有定義入參
// 則直接呼叫這個構造方法建立一個例項物件(反射機制),並返回
if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Constructor<?> uniqueCandidate = candidates[0];
if (uniqueCandidate.getParameterCount() == 0) {
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
mbd.constructorArgumentsResolved = true;
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
// Need to resolve the constructor.
// 是否是構造器注入
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
// 用於承載解析後的方法引數值
ConstructorArgumentValues resolvedValues = null;
// -------------------------確定構造方法的入引數量-------------------------
// <3> 確定構造引數的入引數量,匹配的方法的入引數量要多餘它
// 方法的引數數量的最小值
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
// 從 RootBeanDefinition 解析出方法的引數個數作為最小值
else {
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// <4> 將所有的構造方法進行排序,public 方法優先,入參個數多的優先
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
// 遍歷所有建構函式
for (Constructor<?> candidate : candidates) {
// 獲取該構造方法的引數型別
Class<?>[] paramTypes = candidate.getParameterTypes();
// 如果前面已經找到匹配的構造方法和入參,則直接結束迴圈
if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
// 如果這個構造方法的引數個數小於入引數量,則跳過
if (paramTypes.length < minNrOfArgs) {
continue;
}
// -------------------------解析出構造方法的入參-------------------------
// <5> 解析出構造方法的入參
// 儲存引數的物件
ArgumentsHolder argsHolder;
// <5.2> 通過**依賴注入**獲取入參
if (resolvedValues != null) {
try {
// 獲取構造方法的引數名稱(@ConstructorProperties 註解)
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
// 沒有獲取到則通過 ParameterNameDiscoverer 引數探測器獲取引數名稱
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
// 解析出方法的入參,引數值會被依賴注入
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
// <5.1> 如果當前方法的入參指定了引數,如果個數相等則直接使用
else {
// Explicit arguments given -> arguments length must match exactly.
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
// -------------------------根據權重獲取最匹配的方法-------------------------
// <6> 因為會遍歷所有匹配的方法,所以需要進行權重的判斷,拿到最優先的那個
// 判斷解析建構函式的時候是否以寬鬆模式還是嚴格模式,預設為 true
// 嚴格模式:解析建構函式時,必須所有的都需要匹配,否則丟擲異常
// 寬鬆模式:使用具有"最接近的模式"進行匹配
// typeDiffWeight:型別差異權重
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this constructor if it represents the closest match.
// 代表最匹配的結果,則選擇作為符合條件的方法
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
// <7> 沒有找到對應的構造方法,則丟擲異常
if (constructorToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Could not resolve matching constructor " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
}
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous constructor matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousConstructors);
}
// <8> 將解析出來的工廠方法和入參快取,設定到 RootBeanDefinition 中,因為整個過程比較複雜,避免再次解析
if (explicitArgs == null && argsHolderToUse != null) {
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
Assert.state(argsToUse != null, "Unresolved constructor arguments");
// <9> 呼叫這個構造方法返回一個例項物件(反射機制),並設定到 `bw` 中
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}
這個方法我也是吐了?,不過還好,和上一個方法邏輯差不多,硬著頭皮,參考檔案:ConstructorResolver.java
對於過程不感興趣的可以跳過直接看下面的概括,過程大致如下:
先建立一個 BeanWrapperImpl 物件 bw
,並初始化,設定 ConversionService 型別轉換器,並註冊自定義的屬性編輯器
-
嘗試獲取構造方法和入參
-
如果當前方法入參指定了引數,則直接使用
-
否則,嘗試從 RootBeanDefinition 中獲取已解析出來的構造方法和入參,如果獲取到了未被解析過的入參,則進行解析(型別轉換)
例如給定方法 A(int, int),配置了 A("1"、"2") 兩個引數,則會轉換為 A(1, 1)
-
這一步嘗試獲取兩個物件:constructorToUse
(構造方法)、argsToUse
(構造方法的入參集合)
-
如果上一步沒有找到構造方法或入參集合,找到所有匹配的工廠方法,首先找到所有匹配的構造方法
-
獲取所有的構造方法,如果當前方法指定了構造方法的集合,則使用這個集合
-
如果構造方法只有一個,且當前方法的入參沒有指定引數,且本身也沒有定義引數,且這個構造方法沒有定義入參
則直接呼叫這個構造方法建立一個例項物件(反射機制),並返回
-
上面第 2.2
步,通常只有預設構造方法才會直接呼叫並返回的,否則需要進行接下來的解析過程
- 確定構造引數的入引數量,匹配的方法的入引數量要多餘它
- 將所有的構造方法進行排序,public 方法優先,入參個數多的優先
這一步主要是確定入參的個數,並排序所有匹配的構造方法,接下來會遍歷所有匹配的構造方法
如果前面已經找到匹配的構造方法和入參,則直接結束迴圈;如果這個構造方法的引數個數小於入引數量,則跳過
- 解析出構造方法的入參
- 如果當前方法的入參指定了引數,如果個數相等則直接使用
- 否則,通過構造器注入獲取入參
這一步會找到這個構造方法的入參,構造器注入的方式
- 因為會遍歷所有匹配的方法,所以需要進行權重的判斷,拿到最優先的那個,會根據方法的引數型別進行權重
- 沒有找到對應的構造方法,則丟擲異常
- 將解析出來的工廠方法和入參快取,設定到 RootBeanDefinition 中,因為整個過程比較複雜,避免再次解析
會快取這幾個資料:resolvedConstructorOrFactoryMethod
(已經解析出來的構造方法)、constructorArgumentsResolved
(方法入參已經解析出來了 true)、resolvedConstructorArguments
(解析出來的入參)
- 呼叫這個構造方法返回一個例項物件(反射機制),並設定到
bw
中
上面整個過程非常複雜,這裡進行簡單概括:
-
找到最匹配的構造方法
-
如果構造方法有入參,則需要注入相關物件(構造器注入,其實也是依賴注入獲取到的引數)
-
呼叫這個構造方法(反射機制),返回一個例項物件
instantiateBean 方法
兜底方法,如果構造方法找不到(或者已經解析出來的構造方法),則直接使用預設的構造方法(或者已經解析出來的構造方法),返回一個例項物件,方法如下:
// AbstractAutowireCapableBeanFactory.java
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>) () ->
// 獲得 InstantiationStrategy 物件,並使用它,建立 Bean 物件
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
// 獲得 InstantiationStrategy 物件,並使用它,建立 Bean 物件
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);
}
}
可以看到會通過 CglibSubclassingInstantiationStrategy#instantiate(...)
方法建立一個例項物件,該方法如下:
// SimpleInstantiationStrategy.java
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
// <1> 沒有 MethodOverride 物件,也就是沒有需要覆蓋或替換的方法,則直接使用反射機制進行例項化即可
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
// <1.1> 嘗試從 RootBeanDefinition 獲得已經解析出來的構造方法 `resolvedConstructorOrFactoryMethod`
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
// <1.2> 沒有解析出來的構造方法,則獲取預設的構造方法
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
// 如果是介面,丟擲 BeanInstantiationException 異常
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
// 從 clazz 中,獲得構造方法
if (System.getSecurityManager() != null) { // 安全模式
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
constructorToUse = clazz.getDeclaredConstructor();
}
// 標記 resolvedConstructorOrFactoryMethod 屬性
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// <1.3> 通過這個構造方法例項化一個物件(反射機制)
return BeanUtils.instantiateClass(constructorToUse);
}
// <2> 否則,通過 CGLIB 生成一個子類物件
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
過程大致如下:
- 沒有 MethodOverride 物件,也就是沒有需要覆蓋或替換的方法,則直接使用反射機制進行例項化即可
- 嘗試從 RootBeanDefinition 獲得已經解析出來的構造方法
resolvedConstructorOrFactoryMethod
- 沒有解析出來的構造方法,則獲取預設的構造方法
- 通過這個構造方法例項化一個物件(反射機制)
- 嘗試從 RootBeanDefinition 獲得已經解析出來的構造方法
- 否則,通過 CGLIB 生成一個子類物件,該過程暫時忽略
整個過程並不複雜
總結
當我們顯示或者隱式地呼叫AbstractBeanFactory
的 getBean(...)
方法時,會觸發 Bean 的載入,在《開啟 Bean 的載入》文章中分析了整個載入過程。
對於不同作用域的 Bean,底層都會呼叫 AbstractAutowireCapableBeanFactory
的 createBean(...)
方法進行建立,在上一篇《Bean 的建立過程》文章中分析了整個建立過程。在建立 Bean 的過程中,需要先建立一個例項物件,這個過程在例項化階段完成,主要分為下面幾種情況:
- 指定了 Supplier 例項化回撥介面,則回撥該介面,返回一個例項物件
- 配置了
factory-method
工廠方法建立當前 Bean,則找到這個方法,如果有入參,則需要找到對應的引數(依賴注入),然後建立一個例項物件(@Bean
註解底層原理也是這種方式) - 找到一個最匹配的構造方法,如果有入參則需要找到對應的引數(構造器注入),返回一個例項物件,這個構造方法會設定到這個 RootBeanDefinition 中,避免再次解析,提高效能
- 兜底方法,使用預設構造方法返回一個例項物件