Spring Ioc原始碼分析系列--實體化Bean的幾種方法
前言
前面的文章Spring Ioc原始碼分析系列--Bean實體化程序(二)在講解到bean真正通過那些方式實體化出來的時候,并沒有繼續分析了,而是留到了這里去分析,主要是因為獲取獲取建構式,推斷建構式也是一個比較復雜的操作,就想另起一篇文章再說,但是總的來說,應該不會比前面的邏輯繞,因為這里很清晰,就是實體化物件的幾種方法,那么實體化物件有哪幾種選擇呢?沒印象,那說明前面的文章沒留下影響,回去翻翻,所以廢話少說,跟著上面文章的口子,我們來分析實體化bean的程序,
原始碼分析
首先,這里回憶一下之前說到什么,
本篇文章的核心邏輯入口是在AbstractAutowireCapableBeanFactory#createBeanInstance()方法里,
跟進createBeanInstance(beanName, mbd, args)方法,這個方法干了哪幾件事?
- 首先嘗試呼叫
obtainFromSupplier()實體化bean - 嘗試呼叫
instantiateUsingFactoryMethod()實體化bean - 根據給定引數推斷建構式實體化bean
- 以上均無,則使用默認建構式實體化bean
先貼一下代碼,然后逐個分析,
/**
* Create a new instance for the specified bean, using an appropriate instantiation strategy:
* factory method, constructor autowiring, or simple instantiation.
*
* 使用適當的實體化策略為指定的 bean 創建一個新實體:工廠方法、建構式自動裝配或簡單實體化,
*
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return a BeanWrapper for the new instance
* @see #obtainFromSupplier
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
* @see #instantiateBean
*/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 確保此時實際決議了 bean 類,
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());
}
// 通過bd中提供的instanceSupplier來獲取一個物件
// 正常bd中都不會有這個instanceSupplier屬性,這里也是Spring提供的一個擴展點,但實際上不常用
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//如果工廠方法不為null,則使用工廠方法初始化策略
// bd中提供了factoryMethodName屬性,那么要使用工廠方法的方式來創建物件,
// 工廠方法又會區分靜態工廠方法跟實體工廠方法
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
// 在原型模式下,如果已經創建過一次這個Bean了,那么就不需要再次推斷建構式了
// 是否推斷過建構式
boolean resolved = false;
// 建構式是否需要進行注入
boolean autowireNecessary = false;
if (args == null) {
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);
}
}
// Candidate constructors for autowiring?
//需要根據引數決議建構式
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//建構式自動注入
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
// 默認構造的首選建構式?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
//使用默認建構式
return instantiateBean(beanName, mbd);
}
使用Supplier實體化bean
這一塊的邏輯對應如下
// 通過bd中提供的instanceSupplier來獲取一個物件
// 正常bd中都不會有這個instanceSupplier屬性,這里也是Spring提供的一個擴展點,但實際上不常用
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
Supplier在Spring里面的使用是相對比較新的,看了一個代碼的commit記錄,這一塊的代碼是在2016年12月19號加上的,相對來說還是比較新的,
Supplier就是一個Java 8提供的函式式編程介面,里面提供一個get()方法,可以通過這個方法實體化bean物件,
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
跟進obtainFromSupplier()方法,可以看到邏輯是比較簡單的,通過一個NamedThreadLocal設定依賴關系beanName,然后呼叫instanceSupplier.get()獲取物件,隨后包裝成一個BeanWrapper回傳,
/**
* Obtain a bean instance from the given supplier.
*
* 從給定的 supplier 處獲取一個 bean 實體,
*
* @param instanceSupplier the configured supplier
* @param beanName the corresponding bean name
* @return a BeanWrapper for the new instance
* @since 5.0
* @see #getObjectForBeanInstance
*/
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
Object instance;
// 這里是處理 Supplier 創建的 bean 的內外部名稱依賴關系
String outerBean = this.currentlyCreatedBean.get();
this.currentlyCreatedBean.set(beanName);
try {
// 呼叫 get() 方法獲取物件
instance = instanceSupplier.get();
}
finally {
if (outerBean != null) {
this.currentlyCreatedBean.set(outerBean);
}
else {
this.currentlyCreatedBean.remove();
}
}
if (instance == null) {
instance = new NullBean();
}
BeanWrapper bw = new BeanWrapperImpl(instance);
initBeanWrapper(bw);
return bw;
}
使用工廠方法實體化bean
簡介
這一塊的代碼邏輯對應如下
//如果工廠方法不為null,則使用工廠方法初始化策略
// bd中提供了factoryMethodName屬性,那么要使用工廠方法的方式來創建物件,
// 工廠方法又會區分靜態工廠方法跟實體工廠方法
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
跟進instantiateUsingFactoryMethod()方法,可以看到這里先new了一個ConstructorResolver,這個ConstructorResolver非常重要,它會去推斷合適的建構式,實體化bean另起這篇文章來寫,很大程度就是因為這個ConstructorResolver,我想寫清楚一點,
/**
* Instantiate the bean using a named factory method. The method may be static, if the
* mbd parameter specifies a class, rather than a factoryBean, or an instance variable
* on a factory object itself configured using Dependency Injection.
*
* 使用命名工廠方法實體化 bean,
* 如果 mbd 引數指定一個類,而不是 factoryBean,或者使用依賴注入配置的工廠物件本身的實體變數,則該方法可能是靜態的,
*
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @param explicitArgs argument values passed in programmatically via the getBean method,
* or {@code null} if none (-> use constructor argument values from bean definition)
* @return a BeanWrapper for the new instance
* @see #getBean(String, Object[])
*/
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
首先來看一下ConstructorResolver類上的定義,翻譯一下就是:用于決議建構式和工廠方法的委托,通過引數匹配執行建構式決議,
Delegate for resolving constructors and factory methods.Performs constructor resolution through argument matching.
這個類的作用非常強大,可以決議實體化物件的所需的構造器,如果有多個,會根據構造器的引數型別和給定的引數型別通過計算權重的方式去匹配一個最佳的構造器,
跟進方法instantiateUsingFactoryMethod()代碼,這個方法整整三百行,可以說非常離譜,
這里先貼個圖,看下基本的邏輯,其實邏輯也跟我們寫業務差不多,先做些基礎準備,這里就是初始化個BeanWrapperImpl,給工廠bean屬性賦賦值等,然后就去快取去工廠方法和引數,取不到就去決議獲取方法和引數,然后利用工廠方法和引數,實體化一個物件回傳,邏輯清晰,

下面分段來看一下代碼吧,
基礎屬性賦值
這一塊代碼比較簡單,就是初始化一個BeanWrapperImpl,然后給一些屬性賦值,
// 創建并初始化一個 BeanWrapperImpl
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
// 實體化這個Bean的工廠Bean
Object factoryBean;
// 工廠Bean的Class
Class<?> factoryClass;
// 靜態工廠方法或者是實體化工廠方法
boolean isStatic;
/*下面這段代碼就是為上面申明的這三個屬性賦值*/
String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
// 如果創建這個Bean的工廠就是這個Bean本身的話,那么直接拋出例外
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
// 得到創建這個Bean的工廠Bean
factoryBean = this.beanFactory.getBean(factoryBeanName);
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
factoryClass = factoryBean.getClass();
isStatic = false;
}
else {
// It's a static factory method on the bean class.
// factoryBeanName為null,說明是通過靜態工廠方法來實體化Bean的
// 靜態工廠進行實體化Bean,beanClass屬性必須要是工廠的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;
}
從快取獲取引數
完成準備后,接下來是從快取中獲取工廠方法和引數,這里也比較簡單,跟著注釋看看,這里需要注意resolvedConstructorArguments和preparedConstructorArguments這兩個引數快取,resolvedConstructorArguments 用于快取完全決議的建構式引數的包可見欄位,preparedConstructorArguments 用于快取部分準備好的建構式引數的包可見欄位,其中如果是preparedConstructorArguments 中存在引數的話,需要呼叫resolvePreparedArguments()方法再次進行決議,
// 到這里已經得到了一個BeanWrapper,明確了實體化當前這個Bean到底是靜態工廠還是實體工廠
// 并且已經確定了工廠Bean
//================//
// 最終確定的要用來創建物件的方法
Method factoryMethodToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
// 從快取中決議獲取引數
// 引數分析時已經說過,explicitArgs就是null
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
// 下面這段代碼是什么意思呢?
// 在原型模式下,我們會多次創建一個Bean,所以Spring對引數以及所使用的方法做了快取
// 在第二次創建原型物件的時候會進入這段快取的邏輯
// 但是這里有個問題,為什么Spring對引數有兩個快取呢?
// 一:resolvedConstructorArguments 用于快取完全決議的建構式引數的包可見欄位
// 二:preparedConstructorArguments 用于快取部分準備好的建構式引數的包可見欄位
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
// 快取已經決議過的工廠方法或者構造方法
if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached factory method...
// 找到一個快取的工廠方法...resolvedConstructorArguments 跟 preparedConstructorArguments都是對引數的快取
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
// preparedConstructorArguments需要再次進行決議,其中主要完成了獲取依賴以及型別轉換等作業
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
}
}
跟進resolvePreparedArguments()方法,簡單來說就是根據引數的型別去決議獲取出需要的引數,同時這里也會完成型別轉換,
/**
* Resolve the prepared arguments stored in the given bean definition.
*
* 決議存盤在給定 bean 定義中的準備好的引數,
*
*/
private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
Executable executable, Object[] argsToResolve, boolean fallback) {
// 獲取型別轉換器
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
// 獲取占位符決議器
BeanDefinitionValueResolver valueResolver =
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
Class<?>[] paramTypes = executable.getParameterTypes();
Object[] resolvedArgs = new Object[argsToResolve.length];
// 逐個遍歷引數
for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) {
Object argValue = https://www.cnblogs.com/codegitz/archive/2022/06/06/argsToResolve[argIndex];
MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex);
// 如果是自動裝配標志,則進行依賴決議
if (argValue == autowiredArgumentMarker) {
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, fallback);
}
// 如果是 BeanMetadataElement 型別,則進行各種BeanDefinition的決議,因為 BeanMetadataElement 的實作基本上是各種BeanMetadataElement
else if (argValue instanceof BeanMetadataElement) {
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
}
// String 型別
else if (argValue instanceof String) {
argValue = https://www.cnblogs.com/codegitz/archive/2022/06/06/this.beanFactory.evaluateBeanDefinitionString((String) argValue, mbd);
}
Class<?> paramType = paramTypes[argIndex];
try {
// 進行型別轉換
resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
}
catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),"Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(argValue) +
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
}
return resolvedArgs;
}
決議獲取工廠方法和引數
決議一下這段邏輯,這里會先去獲取該工廠bean的所有方法作為候選方法,然后按照先前賦值的屬性進行簡單篩選,如果非常巧合,只找到了一個,同時引數又為空,這時候就可以利用這個唯一的方法去實體化物件,省略了后面引數決議的復雜邏輯,如果不巧,那就只好老老實實去決議引數匹配,
- 首先這里會對所有方法進行排序,這里會對給定的工廠方法進行排序,優先選擇公共方法和具有最多引數的“貪婪”方法,結果將首先包含公共方法,引數數量減少,然后是非公共方法,引數數量再次減少,
- 然后會呼叫
resolveConstructorArguments()去獲取可執行方法的最少引數個數minNrOfArgs, - 隨后遍歷所有的候選方法,方法的引數個數必須滿足大于或等于可執行方法的最少引數個數
minNrOfArgs,嘗試通過方法引數名稱,方法引數型別和給定的resolvedValues屬性里面去查找或者通過自動注入獲取到引數值,然后封裝成ArgumentsHolder物件, - 如果存在多個,通過權重計算獲取最合適的工廠方法,如果最后沒有找到工廠方法和引數,直接報錯,如果最合適的有多個,那么也直接報錯,
- 最后對工廠方法和引數進行快取,然后呼叫
instantiate()方法,使用前面決議出來的工廠方法和引數進行物件創建,
具體實作如下,可以跟著注釋查看,這里就不全部再去決議,下面就簡單分析一下確定方法執行所需的最小引數和封裝ArgumentsHolder物件的邏輯,
// 快取中找不到方法獲取引數,執行到這段代碼說明是第一次實體化這個物件
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.
// 需要確定工廠方法...嘗試所有具有此名稱的方法,看看它們是否與給定的引數匹配,
// 如果被cglib代理的話,獲取父類的class
factoryClass = ClassUtils.getUserClass(factoryClass);
// 獲取到工廠類中的所有方法
List<Method> candidateList = null;
if (mbd.isFactoryMethodUnique) {
if (factoryMethodToUse == null) {
factoryMethodToUse = mbd.getResolvedFactoryMethod();
}
if (factoryMethodToUse != null) {
candidateList = Collections.singletonList(factoryMethodToUse);
}
}
if (candidateList == null) {
candidateList = new ArrayList<>();
// 獲取到工廠類中的所有方法,接下來要一步步從這些方法中篩選出來符合要求的方法
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
// 第一步篩選:之前 在第二段代碼中已經推斷了方法是靜態或者非靜態的
// 所以這里第一個要求就是要滿足靜態/非靜態這個條件
// 第二個要求就是必須符合bd中定義的factoryMethodName的名稱
// 其中第二個要求請注意,如果bd是一個configurationClassBeanDefinition,
// 也就是說是通過掃描@Bean注解產生的,那么在判斷時還會添加是否標注了@Bean注解
for (Method candidate : rawCandidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
candidateList.add(candidate);
}
}
}
// 如果只有一個,則沒有多載方法,不需要查找,這里就會省略后續復雜的推斷了,可以直接確定方法
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;
}
}
// 將之前得到的方法集合轉換成陣列
// 到這一步得到的其實就是某一個方法的所有多載方法
// 比如 codegitz(),codegitz(String name),codegitz(String name,int age)
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;
int minNrOfArgs;
// 必定為null,不考慮了
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
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.
// 就是說組態檔中指定了要使用的引數,那么需要對其進行決議,決議后的值就存盤在resolvedValues這個集合中
if (mbd.hasConstructorArgumentValues()) {
// 通過決議constructor-arg標簽,將引數封裝成了ConstructorArgumentValues
// ConstructorArgumentValues這個類在下文我們專門分析
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
// 決議標簽中的屬性,類似進行型別轉換,后文進行詳細分析
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
else {
// 組態檔中沒有指定要使用的引數,所以執行方法的最小引數個數就是0
minNrOfArgs = 0;
}
}
LinkedList<UnsatisfiedDependencyException> causes = null;
for (Method candidate : candidates) {
Class<?>[] paramTypes = candidate.getParameterTypes();
if (paramTypes.length >= minNrOfArgs) {
ArgumentsHolder argsHolder;
if (explicitArgs != null) {
// Explicit arguments given -> arguments length must match exactly.
// 給定的顯式引數 -> 引數長度必須完全匹配,
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
else {
// Resolved constructor arguments: type conversion and/or autowiring necessary.
// 已解決的建構式引數:需要型別轉換和自動裝配,
try {
String[] paramNames = null;
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) {
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;
}
}
// 計算給定引數和方法定義引數的權重,選擇一個最合適的方法
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).
// 找出歧義:如果具有相同數量的引數的方法的型別差異權重相同,則收集此類候選并最終引發歧義例外,
// 但是,僅在非寬松建構式決議模式下執行該檢查,并顯式忽略重寫的方法(具有相同的引數簽名)
// 可以理解為,這里就是收集引數型別和數量一樣,方法名一樣,如果存在這種情況,最侄訓拋出例外
// 為啥會出現這種情況,我理解可能是同名方法引數的順序不一樣導致的,例如 sayHi(String name,String age) 和 sayHi(String age,String name)
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);
}
}
}
// 最終沒有找到可用的工廠方法或者引數,或者有多個符合要求的方法等情況,進行例外處理
if (factoryMethodToUse == null || argsToUse == null) {
// 省略一些例外處理...
}
// 快取引數
if (explicitArgs == null && argsHolderToUse != null) {
mbd.factoryMethodToIntrospect = factoryMethodToUse;
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
}
簡單的邏輯就不做過多解釋了,這里重點來看下是怎么確定方法最小使用引數個數的,跟進代碼resolveConstructorArguments(),該方法會先獲取constructor-arg標簽指定的引數個數,然后去獲取引數的下標值,如果下標值更大,那么最小的引數個數就取下標值加一,
/**
* Resolve the constructor arguments for this bean into the resolvedValues object.
* This may involve looking up other beans.
* <p>This method is also used for handling invocations of static factory methods.
*
* 將此 bean 的建構式引數決議為 resolvedValues 物件,這可能涉及查找其他 bean,
* <p>此方法也用于處理靜態工廠方法的呼叫,
*
* 方法目的:決議組態檔中指定的方法引數
* beanName:bean名稱
* mbd:beanName對應的beanDefinition
* bw:通過它進行型別轉換
* ConstructorArgumentValues cargs:決議標簽得到的屬性,還沒有經過決議(型別轉換)
* ConstructorArgumentValues resolvedValues:已經經過決議的引數
* 回傳值:回傳方法需要的最小引數個數
*
*/
private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {
// 是否有定制的型別轉換器,沒有的話直接使用BeanWrapper進行型別轉換
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
// 構造一個BeanDefinitionValueResolver,專門用于決議constructor-arg中的value屬性,實際上還包括ref屬性,內嵌bean標簽等等
BeanDefinitionValueResolver valueResolver =
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
// minNrOfArgs 記錄執行方法要求的最小引數個數,一般情況下就是等于constructor-arg標簽指定的引數數量
int minNrOfArgs = cargs.getArgumentCount();
for (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) {
int index = entry.getKey();
if (index < 0) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Invalid constructor argument index: " + index);
}
// 這是啥意思呢?
// 暫且你先這樣理解
// 假設A方法直接在組態檔中指定了index=3上要使用的引數,那么這個時候A方法至少需要4個引數
// 但是其余的3個引數可能不是通過constructor-arg標簽指定的,而是直接自動注入進來的,那么在組態檔中我們就只配置了index=3上的引數,也就是說 int minNrOfArgs = cargs.getArgumentCount()=1,這個時候 index=3,minNrOfArgs=1, 所以 minNrOfArgs = 3+1
if (index > minNrOfArgs) {
minNrOfArgs = index + 1;
}
ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue();
if (valueHolder.isConverted()) {
// 如果已經轉換過了,直接添加到resolvedValues集合中
resolvedValues.addIndexedArgumentValue(index, valueHolder);
}
else {
// 決議value/ref/內嵌bean標簽等
Object resolvedValue =
https://www.cnblogs.com/codegitz/archive/2022/06/06/valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
// 將決議后的resolvedValue封裝成一個新的ValueHolder,
// 并將其source設定為決議constructor-arg得到的那個ValueHolder,
// 后期會用到這個屬性進行判斷
ConstructorArgumentValues.ValueHolder resolvedValueHolder =
new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
}
}
// 對getGenericArgumentValues進行決議,代碼基本一樣,不再贅述
for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) {
if (valueHolder.isConverted()) {
resolvedValues.addGenericArgumentValue(valueHolder);
}
else {
Object resolvedValue =
https://www.cnblogs.com/codegitz/archive/2022/06/06/valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(
resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addGenericArgumentValue(resolvedValueHolder);
}
}
return minNrOfArgs;
}
看完怎么確定最小方法引數個數的邏輯,接下來需要按照給定決議的建構式引數值,創建一個引數陣列以呼叫建構式或工廠方法,就看一下封裝ArgumentsHolder物件的程序,跟進代碼createArgumentArray()方法查看,
這方法也沒啥好說,就是逐個去獲取,如果給定的引數沒有,那就從容器中獲取,這部分即為自動注入的引數,
/**
* Create an array of arguments to invoke a constructor or factory method,
* given the resolved constructor argument values.
*
* 給定決議的建構式引數值,創建一個引數陣列以呼叫建構式或工廠方法,
*/
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
Class<?> paramType = paramTypes[paramIndex];
String paramName = (paramNames != null ? paramNames[paramIndex] : "");
// Try to find matching constructor argument value, either indexed or generic.
// 嘗試找到匹配的建構式引數值,無論是索引的還是泛型的,
ConstructorArgumentValues.ValueHolder valueHolder = null;
if (resolvedValues != null) {
valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
// If we couldn't find a direct match and are not supposed to autowire,
// let's try the next generic, untyped argument value as fallback:
// it could match after type conversion (for example, String -> int).
// 如果我們找不到直接匹配并且不應該自動裝配,讓我們嘗試下一個通用的、無型別的引數值作為后備:它可以在型別轉換后匹配(例如,String -> int),
if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
}
}
if (valueHolder != null) {
// We found a potential match - let's give it a try.
// Do not consider the same value definition multiple times!
// 我們找到了一個潛在的匹配 - 讓我們試一試,不要多次考慮相同的值定義!
usedValueHolders.add(valueHolder);
Object originalValue = https://www.cnblogs.com/codegitz/archive/2022/06/06/valueHolder.getValue();
Object convertedValue;
if (valueHolder.isConverted()) {
convertedValue = valueHolder.getConvertedValue();
args.preparedArguments[paramIndex] = convertedValue;
}
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
try {
convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
}
catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),"Could not convert argument value of type [" +
ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
Object sourceHolder = valueHolder.getSource();
if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
Object sourceValue = https://www.cnblogs.com/codegitz/archive/2022/06/06/((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
args.resolveNecessary = true;
args.preparedArguments[paramIndex] = sourceValue;
}
}
args.arguments[paramIndex] = convertedValue;
args.rawArguments[paramIndex] = originalValue;
}
else {
// 這部分就是超出了引數定義,需要自動注入引數的處理
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
// No explicit match found: we're either supposed to autowire or
// have to fail creating an argument array for the given constructor.
if (!autowiring) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
"Ambiguous argument values for parameter of type [" + paramType.getName() +
"] - did you specify the correct bean references as arguments?");
}
try {
Object autowiredArgument = resolveAutowiredArgument(
methodParam, beanName, autowiredBeanNames, converter, fallback);
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = autowiredArgumentMarker;
args.resolveNecessary = true;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
}
}
}
for (String autowiredBeanName : autowiredBeanNames) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName +
"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
" to bean named '" + autowiredBeanName + "'");
}
}
return args;
}
實體化bean
工廠方法和引數都已經獲取完成了,到最后就是呼叫instantiate()方法去實體化一個bean物件,跟進instantiate()方法查看代碼,可以看到這里就是確定一個構造策略,然后呼叫其instantiate()方法,
private Object instantiate(String beanName, RootBeanDefinition mbd,
@Nullable Object factoryBean, Method factoryMethod, Object[] args) {
try {
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedAction<Object>) () ->
this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args),
this.beanFactory.getAccessControlContext());
}
else {
// 確定實體化策略,呼叫其 instantiate() 方法,
// 該方法有兩種實作,
// 一種是普通的實作 SimpleInstantiationStrategy,
// 一種是需要使用到代理的 CglibSubclassingInstantiationStrategy 實作
return this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args);
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via factory method failed", ex);
}
}
我們看一下普通的實作SimpleInstantiationStrategy#instantiate(),跟進代碼查看,可以看到邏輯還是比較簡單的,就是完成一些基礎設定,然后直接呼叫方法獲取物件回傳,至此,使用工廠方法實體化bean的分析已經完成了,
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Object factoryBean, final Method factoryMethod, Object... args) {
try {
// 權限相關,暫時忽略...
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(factoryMethod);
return null;
});
}
else {
// 設定訪問標識
ReflectionUtils.makeAccessible(factoryMethod);
}
// 記錄上一個呼叫的工廠方法
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
try {
// 設定當前呼叫的工廠方法
currentlyInvokedFactoryMethod.set(factoryMethod);
// 直接呼叫工廠方法獲取物件
Object result = factoryMethod.invoke(factoryBean, args);
if (result == null) {
result = new NullBean();
}
// 回傳物件
return result;
}
finally {
// 后續狀態的設定
if (priorInvokedFactoryMethod != null) {
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
}
else {
currentlyInvokedFactoryMethod.remove();
}
}
}
catch (IllegalArgumentException ex) {
// 省略部分例外處理...
}
}
使用有參建構式實體化bean
還是回到AbstractAutowireCapableBeanFactory#createBeanInstance()方法里,如果經過了前面兩種處理都沒有獲得一個實體化的物件的話,那么接下來就要使用建構式去實體化物件了,
建構式分為有參建構式和無參建構式,在這里會先匹配有參建構式,然后再去使用默認的無參建構式,
這里先討論使用有參建構式的情況,啥時候使用有參建構式呢?在這里看來無非是兩種:
- 指定了一個建構式,spring提供了一個
determineConstructorsFromBeanPostProcessors()方法來提供一個擴展口回傳一個建構式, - 傳入的引數不為空,這里會進入到
autowireConstructor()方法里進行推斷建構式,這里的推斷程序跟上面工廠方法推斷程序非常類似,可以參考著看看,
先來看看指定一個建構式是怎么處理,跟進determineConstructorsFromBeanPostProcessors()方法,這里可以看到就是呼叫了SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors()方法,沒啥特別的,
/**
* Determine candidate constructors to use for the given bean, checking all registered
* {@link SmartInstantiationAwareBeanPostProcessor SmartInstantiationAwareBeanPostProcessors}.
*
* 確定用于給定 bean 的候選建構式,檢查所有已注冊的 {@link SmartInstantiationAwareBeanPostProcessor SmartInstantiationAwareBeanPostProcessors},
*
* @param beanClass the raw class of the bean
* @param beanName the name of the bean
* @return the candidate constructors, or {@code null} if none specified
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
*/
@Nullable
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
throws BeansException {
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
}
return null;
}
接下來看重點autowireConstructor()方法,這里的實作邏輯也是委派給了ConstructorResolver去實作,
/**
* "autowire constructor" (with constructor arguments by type) behavior.
* Also applied if explicit constructor argument values are specified,
* matching all remaining arguments with beans from the bean factory.
* <p>This corresponds to constructor injection: In this mode, a Spring
* bean factory is able to host components that expect constructor-based
* dependency resolution.
*
* “自動裝配建構式”(按型別使用建構式引數)行為,
* 如果指定了顯式建構式引數值,也適用,將所有剩余引數與 bean 工廠中的 bean 匹配,
* <p>這對應于建構式注入:在這種模式下,Spring bean 工廠能夠托管期望基于建構式的依賴決議的組件,
*
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @param ctors the chosen candidate constructors
* @param explicitArgs argument values passed in programmatically via the getBean method,
* or {@code null} if none (-> use constructor argument values from bean definition)
* @return a BeanWrapper for the new instance
*/
protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
跟進autowireConstructor()方法,可以看到這里的邏輯跟工廠方法的決議是非常類似的,根據引數去推斷合適的方法,然后獲取引數的依賴,最后利用獲取到的構造方法和引數實體化物件,詳細可見上一節,這里不再贅述,
/**
* "autowire constructor" (with constructor arguments by type) behavior.
* Also applied if explicit constructor argument values are specified,
* matching all remaining arguments with beans from the bean factory.
* <p>This corresponds to constructor injection: In this mode, a Spring
* bean factory is able to host components that expect constructor-based
* dependency resolution.
*
* “自動裝配建構式”(按型別使用建構式引數)行為,
* 如果指定了顯式建構式引數值,也適用,將所有剩余引數與 bean 工廠中的 bean 匹配,
* <p>這對應于建構式注入:在這種模式下,Spring bean 工廠能夠托管期望基于建構式的依賴決議的組件,
*
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param chosenCtors chosen candidate constructors (or {@code null} if none)
* @param explicitArgs argument values passed in programmatically via the getBean method,
* or {@code null} if none (-> use constructor argument values from bean definition)
* 通過 getBean 方法以編程方式傳入的引數值,如果沒有則 {@code null}(-> 使用 bean 定義中的建構式引數值)
* @return a BeanWrapper for the new instance
*/
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
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) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果 mbd 存在待決議的引數,直接進行決議
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
// 快取中沒有同時存在構造器和引數,老老實實去創建獲取
if (constructorToUse == null || argsToUse == null) {
// Take specified constructors, if any.
// 采用指定的建構式,如果有的話,
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);
}
}
// 如果只有一個構造器,且無指定的引數并且沒有已決議的引數,直接使用該建構式實體化物件回傳
if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Constructor<?> uniqueCandidate = candidates[0];
// 如果這個唯一的建構式是無參建構式,設定 mbd 屬性,實體化后回傳
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;
int minNrOfArgs;
// 確定最少引數的個數
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
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;
}
ArgumentsHolder argsHolder;
if (resolvedValues != null) {
try {
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
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;
}
}
else {
// Explicit arguments given -> arguments length must match exactly.
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
// 獲取建構式和給定引數間的型別權重
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);
}
}
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);
}
if (explicitArgs == null && argsHolderToUse != null) {
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
Assert.state(argsToUse != null, "Unresolved constructor arguments");
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}
使用默認建構式實體化bean
如果前面的邏輯都沒有獲取到一個實體化bean,那么就會走到最后的默認邏輯instantiateBean()里,這里會使用默認的建構式去實體化一個bean回傳,
跟進instantiateBean()方法代碼查看,
/**
* Instantiate the given bean using its default constructor.
*
* 使用其默認建構式實體化給定的 bean,
*
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return a BeanWrapper for the new instance
*/
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 {
// 使用默認的實體化策略來實體化物件,默認為 CglibSubclassingInstantiationStrategy 實作,但是instantiate()方法只在SimpleInstantiationStrategy里有實作邏輯
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);
}
}
進入SimpleInstantiationStrategy#instantiate()方法,這里獲取了默認的建構式,然后呼叫BeanUtils.instantiateClass(constructorToUse)實體化物件,注意這里沒有傳入構造引數,
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
/**
* 如果需要覆寫或者動態替換方法,則使用cglib進行動態代理
* 因為可以在創建動態代理的同時將動態方法織入類中
* 如果沒有需要改變的方法,為了方便直接反射即可
*/
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
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);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
跟進BeanUtils.instantiateClass(constructorToUse)的實作,這里注意,我們上一步并沒有傳入引數,這里使用的是無參建構式,最后是呼叫了 ctor.newInstance(argsWithDefaultValues)實體化一個物件回傳,至此,所有實體化物件的方法都已經分析完成,
/**
* Convenience method to instantiate a class using the given constructor.
* <p>Note that this method tries to set the constructor accessible if given a
* non-accessible (that is, non-public) constructor, and supports Kotlin classes
* with optional parameters and default values.
*
* 使用給定建構式實體化類的便捷方法,
* <p>請注意,如果給定一個不可訪問(即非公共)建構式,
* 此方法會嘗試將建構式設定為可訪問,并且支持帶有可選引數和默認值的 Kotlin 類,
*
* @param ctor the constructor to instantiate
* @param args the constructor arguments to apply (use {@code null} for an unspecified
* parameter, Kotlin optional parameters and Java primitive types are supported)
* @return the new instance
* @throws BeanInstantiationException if the bean cannot be instantiated
* @see Constructor#newInstance
*/
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
return KotlinDelegate.instantiateClass(ctor, args);
}
else {
// 獲取構造器的引數
Class<?>[] parameterTypes = ctor.getParameterTypes();
Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
Object[] argsWithDefaultValues = new Object[args.length];
// 遍歷獲取傳入的 args 引數
for (int i = 0 ; i < args.length; i++) {
if (args[i] == null) {
Class<?> parameterType = parameterTypes[i];
argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
}
else {
argsWithDefaultValues[i] = args[i];
}
}
return ctor.newInstance(argsWithDefaultValues);
}
}
catch (InstantiationException ex) {
// 省略部分例外處理...
}
}
總結
這篇文章主要是分析了實體化bean的幾種方法,有哪幾種?紙面上來看是四種,但是從實際來看,后面的三種都是確定一個函式以及函式的引數來實體化一個物件,有異曲同工之妙,可以細細品味,我們實體化物件如果不指定的話,默認用的都是無參建構式,
總的來說這篇文章比較簡單,就講了實體化物件這一件事情,相比較之前兜兜轉轉的邏輯來說可能相對層次淺一點,這篇文章的難點在于理解方法和函式之間的匹配,怎么通過型別權重去確定一個最佳方法,這里需要花點時間琢磨一下,
個人水平有限,如有錯誤,還請指出,
如果有人看到這里,那在這里老話重提,與君共勉,路漫漫其修遠兮,吾將上下而求索,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/488701.html
標籤:其他
