前言
本系列全部基於 Spring 5.2.2.BUILD-SNAPSHOT
版本。因為 Spring 整個體系太過於龐大,所以只會進行關鍵部分的原始碼解析。
本篇文章主要介紹 Spring IoC 容器是怎麼建立 bean
的例項。
正文
在上一篇Spring IoC bean 的載入中有這麼一段程式碼:
if (mbd.isSingleton()) {
// 建立和註冊單例 bean
sharedInstance = getSingleton(beanName, () -> {
try {
// 建立 bean 例項
return createBean(beanName, mbd, args);
}
// 省略異常處理...
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
如果 bean
的作用域是單例,會呼叫 getSingleton()
方法並傳入 beanName
和 ObjectFacoty
作為引數;而 getSingleton()
方法會呼叫 ObjectFactory
的 getObject()
方法也就是上面程式碼中的 createBean()
方法,返回 bean
。
這裡的 ObjectFactory
是 bean
的延遲依賴查詢介面,定義如下:
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
只有在呼叫 getObject()
方法時才會真正去獲取 bean
。下面我們正式開始分析 createBean()
方法。
AbstractAutowireCapableBeanFactory#createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
// 將String型別的class字串,轉換為Class物件,例如在XML中配置的class屬性
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
// 進行定義的方法覆蓋
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex);
}
try {
// 如果bean的例項化前回撥方法返回非null,直接返回例項,跳過後面步驟。見下文詳解
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex);
}
try {
// 真正去建立bean的方法
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
// 返回bean的例項
return beanInstance;
}
// 省略異常處理...
}
bean 例項化前置處理
我們先看一下 InstantiationAwareBeanPostProcessor
介面的定義:
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
/**
* Bean 例項化前呼叫,返回非 {@code null} 回撥過後面流程
* 返回 {@code null} 則進行 IoC 容器對 Bean 的例項化
*/
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
/**
* Bean 例項化之後,屬性填充之前呼叫,返回 {@code true} 則進行預設的屬性填充步驟,
* 返回 {@code false} 會跳過屬性填充階段,同樣也會跳過初始化階段的生命週期方法的回撥。
*/
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
/**
* Bean 例項化後屬性賦值前呼叫,PropertyValues 是已經封裝好的設定的屬性值,返回 {@code null} 繼續
*/
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
return null;
}
/**
* 5.1 版本後已經被上面 postProcessProperties 方法所替代,功能與上面方法一樣
*/
@Deprecated
@Nullable
default PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
上面介面繼承於 BeanPostProcessor
(BeanPostProcessor
中定義了 bean
的初始化階段生命週期回撥方法,會在後續介紹)提供了三個擴充套件點,如下:
bean
例項化前bean
例項化後bean
屬性賦值前
這也是 bean
例項化階段的生命週期回撥方法。
AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
// 判斷bean在例項化之前是否已經解析過
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// 如果bean是合成的 && 有實現 InstantiationAwareBeanPostProcessor 介面
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 解析bean的型別
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 執行bean的例項化前回撥
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
// 如果例項化前生命週期回撥方法返回的不是null
if (bean != null) {
// 執行bean的例項化後回撥,因為會跳過後續步驟,所以只能在此處呼叫了
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
// 如果bean不為空,則將beforeInstantiationResolved賦值為true,代表在例項化之前已經解析
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
建立 bean
AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
// 例項化 bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 如果bean的作用域是singleton,則需要移除未完成的FactoryBean例項的快取
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 通過建構函式反射建立bean的例項,但是屬性並未賦值,見下文詳解
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 獲取bean的例項
final Object bean = instanceWrapper.getWrappedInstance();
// 獲取bean的型別
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// BeanDefinition 合併後的回撥,見下文詳解
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
// 省略異常處理...
mbd.postProcessed = true;
}
}
// bean的作用域是單例 && 允許迴圈引用 && 當前bean正在建立中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
// 如果允許bean提前曝光
if (earlySingletonExposure) {
// 將beanName和ObjectFactory形成的key-value對放入singletonFactories快取中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 給 bean 的屬性賦值
populateBean(beanName, mbd, instanceWrapper);
// 初始化 bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 省略異常處理...
// 如果允許單例bean提前暴露
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
// 只有在檢測到迴圈依賴的情況下才不為空
if (earlySingletonReference != null) {
// 如果exposedObject沒有在初始化方法中被改變,也就是沒有被增強
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
// 檢測依賴
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
try {
// 用於註冊銷燬bean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
} catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
// 返回bean例項
return exposedObject;
}
建立 bean 的例項
AbstractAutowireCapableBeanFactory#createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 解析 bean 的型別
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 判斷beanClass是否是public修飾的類,並且是否允許訪問非公共建構函式和方法,不是丟擲異常
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());
}
// Spring 5新新增的,如果存在Supplier回撥,則使用給定的回撥方法初始化策略。
// 可以使RootBeanDefinition#setInstanceSupplier()設定
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 如果設定工廠方法則使用給定的方法建立bean例項,這裡分為靜態工廠和例項化工廠
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 快捷方式建立相同的bean
// resolved: 建構函式或工廠方法是否已經解析過
boolean resolved = false;
// autowireNecessary: 是否需要自動注入 (即是否需要解析建構函式)
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// 如果resolvedConstructorOrFactoryMethod不為空,代表建構函式或工廠方法已經解析過
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
// 根據constructorArgumentsResolved判斷是否需要自動注入
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
// 如果建構函式或工廠方法已經解析過並且需要自動注入,則執行構造器自動注入,見下文詳解
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 否則使用預設建構函式進行bean例項化,見下文詳解
return instantiateBean(beanName, mbd);
}
}
// 呼叫SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors()方法
// 拿到 bean 的候選建構函式
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 候選建構函式不為空 || 建構函式依賴注入 || 定義了建構函式的引數值 || args不為空,則執行構造器自動注入
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 如果有首選的建構函式,使用該建構函式去建立bean例項
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// 沒有特殊處理,使用預設無參構造器例項化bean
return instantiateBean(beanName, mbd);
}
上面方法主要判斷是使用建構函式自動注入,還是使用預設建構函式構造。總結起來以下幾種情況會使用建構函式自動注入:
- 已經快取過建構函式並且建構函式的引數已經解析過。
- 候選的建構函式不為空,這裡的候選建構函式是通過實現
SmartInstantiationAwareBeanPostProcessor
介面中的determineCandidateConstructors()
方法 - 自動注入模式為建構函式自動注入
BeanDefinition
定義了建構函式引數,如 XML 中的<constructor-arg index="0" value="1"/>
- 在呼叫
getBean()
方法時顯示指定了args
引數
上面方法中還有一個判斷是否有快取的過程,是因為一個 bean
對應的類中可能會有多個建構函式,而每個建構函式的引數不同,Spring 在根據引數及型別去判斷最終會使用哪個建構函式進行例項化。但是,判斷的過程是個比較消耗效能的步驟,所以採用快取機制,如果已經解析過則不需要重複解析而是直接從 RootBeanDefinition
中的屬性 resolvedConstructorOrFactoryMethod
快取的值去取,否則需要再次解析,並將解析的結果新增至 RootBeanDefinition
中的屬性 resolvedConstructorOrFactoryMethod
中。
這裡簡單介紹一下 SmartInstantiationAwareBeanPostProcessor
這個介面,它繼承於 InstantiationAwareBeanPostProcessor
,如下:
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
/**
* 預測 bean 的型別
*/
@Nullable
default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
/**
* 選擇合適的構造器,比如目標物件有多個構造器,在這裡可以進行一些定製化,選擇合適的構造器
*/
@Nullable
default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
/**
* 獲得提前暴露的 bean 引用,主要用於解決迴圈引用的問題
* 只有單例物件才會呼叫此方法
*/
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}
}
其實我們熟知的 @Autowired
註解標註在建構函式上實現自動注入,也是重寫了該介面的 determineCandidateConstructors()
方法實現的。
預設無參構造器例項化 bean
AbstractAutowireCapableBeanFactory#instantiateBean
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
// 使用指定的策略去實力化bean
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
// 將例項化後的bean封裝成BeanWrapper後返回
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
// 省略異常處理...
}
// SimpleInstantiationStrategy.java
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// 如果有需要覆蓋或者動態替換的方法則當然需要使用CGLIB進行動態代理,因為可以在建立代理的同時將方法織入類中
// 但是如果沒有需要動態改變的方法,為了方便直接用反射就可以了
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
// 獲取快取的構造方法或工廠方法
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
// 快取為空
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
// 如果clazz是介面,丟擲異常
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
// 獲取預設的無參建構函式
constructorToUse = clazz.getDeclaredConstructor();
// 設定快取
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 這裡就是用指定的無參構造器去例項化該bean,不做具體分析了
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// 用CGLIB生成子類動態織入重寫的方法
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
尋找合適的構造器例項化 bean
ConstructorResolver#autowireConstructor
protected BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
// 尋找適合的構造器,進行例項化
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
// 最終例項化的建構函式
Constructor<?> constructorToUse = null;
// 最終用於例項化的引數Holder
ArgumentsHolder argsHolderToUse = null;
// 最終用於例項化的建構函式引數
Object[] argsToUse = null;
// 如果explicitArgs不為空,則使用explicitArgs當做構造器函式引數
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
// 獲取已經快取的建構函式或工廠方法
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// 獲取已經快取的建構函式引數
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 如果已經快取了建構函式或工廠方法,
// 那麼resolvedConstructorArguments和preparedConstructorArguments必定有一個快取了建構函式引數
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
// 如果argsToResolve不為空,則對建構函式引數進行解析,也就是會進行型別轉換之類的操作
// 例如 A(int,int),把配置中的 ("1","1") 轉換為 (1,1)
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
// 如果沒有快取建構函式或者其引數
if (constructorToUse == null || argsToUse == null) {
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
// 如果允許訪問非public的建構函式和方法(該值預設為 true),就獲取所有建構函式,否則只獲取public修飾的建構函式
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);
}
}
// 如果只有一個建構函式 && getBean()沒有顯示指定args && 沒有定義建構函式的引數值
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;
}
// 通過無參建構函式建立bean的例項,然後直接返回
bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
// 如果候選建構函式不為空 || 建構函式自動注入模式
boolean autowiring = (chosenCtors != null || mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
int minNrOfArgs;
// getBean()顯示指定了引數,獲取引數長度
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
// 獲取定義的建構函式引數
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
// 解析建構函式引數並賦值到resolvedValues,返回引數個數。見下文詳解
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// 這裡對建構函式進行排序,規則是首先是public建構函式且引數個數從多到少,然後是非public建構函式且引數個數有多到少
AutowireUtils.sortConstructors(candidates);
// 最小匹配權重,權重越小,越接近我們要找的目標建構函式
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
// 遍歷建構函式,找出符合的建構函式
for (Constructor<?> candidate : candidates) {
// 獲取引數數量
int parameterCount = candidate.getParameterCount();
// 如果已經找到滿足的建構函式 && 目標建構函式引數個數大於當前遍歷的建構函式引數個數則終止
// 因為建構函式已經是排過序的,後面不會再有更適合的了
if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
break;
}
// 如果目標的建構函式引數個數小於我們需要的,直接跳過
if (parameterCount < minNrOfArgs) {
continue;
}
ArgumentsHolder argsHolder;
// 獲取到建構函式的引數型別
Class<?>[] paramTypes = candidate.getParameterTypes();
if (resolvedValues != null) {
try {
// 評估引數名稱,就是判斷建構函式上是否標註了@ConstructorProperties註解,如果標註了,直接取其中定義的引數名稱
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
// 沒有標註@ConstructorProperties註解,使用引數名稱解析器,獲取引數名稱
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
// 建立一個引數陣列以呼叫建構函式或工廠方法,見下文詳解
// 主要是通過引數型別和引數名解析建構函式或工廠方法所需的引數(如果引數是其他bean,則會解析依賴的bean)
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
// resolvedValues為空, explicitArgs不為空,即顯示指定了getBean()的args引數
else {
// 如果當前建構函式引數個數不等的explicitArgs的長度,直接跳過該建構函式
if (parameterCount != explicitArgs.length) {
continue;
}
// 把explicitArgs封裝進ArgumentsHolder
argsHolder = new ArgumentsHolder(explicitArgs);
}
// 根據mbd的解析建構函式模式(true: 寬鬆模式,false:嚴格模式)
// 將argsHolder的引數和paramTypes進行比較,計算paramTypes的型別差異權重值
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// 差異值越小代表建構函式越匹配,則選擇此建構函式
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
// 如果出現權重值更小的候選者,則將ambiguousConstructors清空,允許之前存在權重值相同的候選者
ambiguousConstructors = null;
}
// 兩個候選者權重值相同,並且是當前遍歷過權重值最小的
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
// 將兩個候選者新增到ambiguousConstructors
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);
}
// getBean()方法沒有指定args引數 && 建構函式引數不為空
if (explicitArgs == null && argsHolderToUse != null) {
// 快取解析過後的建構函式和引數
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
Assert.state(argsToUse != null, "Unresolved constructor arguments");
// 利用反射建立bean例項
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}
上面方法的功能主要如下:
- 建構函式引數的確定
- 如果
explicitArgs
引數不為空,那就可以直接確定引數。因為explicitArgs
引數是在呼叫getBean()
時手動指定的,這個主要用於靜態工廠方法的呼叫。 - 快取中不為空,那麼可以直接拿過來使用。
BeanDefinition
中讀取,我們所定義的bean
都會生成一個BeanDefinition
,其中記錄了定義了建構函式引數通過getConstructorArgumentValues()
獲取。
- 如果
- 建構函式的確定。經過第一步已經確定建構函式的引數,接下來就是用引數個數在所有的建構函式中鎖定對應的建構函式。匹配之前會對建構函式進行排序,首先是
public
建構函式且引數個數從多到少,然後是非public
建構函式且引數個數有多到少。這樣可以迅速判斷排在後面的建構函式引數個數是否符合條件。 - 根據對應的建構函式轉換對應的引數型別。
- 根據例項化策略以及得到的建構函式和建構函式引數例項化
bean
。
解析建構函式引數
ConstructorResolver#resolveConstructorArguments
private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {
// 獲取自定義型別轉換器
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
// 如果沒有自定義的轉換器就用bw
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
// minNrOfArgs初始化為indexedArgumentValues+genericArgumentValues的個數總和
int minNrOfArgs = cargs.getArgumentCount();
// 遍歷IndexArgumentValues,這裡的IndexArgumentValues就帶下標的,如:<constructor-arg index="0" value="1"/>
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);
}
// 如果index大於minNrOfArgs,修改minNrOfArgs值
if (index > minNrOfArgs) {
// 因為index是建構函式下標值,所以總數這邊要加1
minNrOfArgs = index + 1;
}
ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue();
// 如果引數型別已經轉換過,直接新增進resolvedValues
if (valueHolder.isConverted()) {
resolvedValues.addIndexedArgumentValue(index, valueHolder);
}
// 引數型別沒有轉換過,進行轉換
else {
Object resolvedValue =
valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
// 使用轉換過的引數值構建ValueHolder
ConstructorArgumentValues.ValueHolder resolvedValueHolder =
new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
// 新增進resolvedValues
resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
}
}
// 遍歷GenericArgumentValues並進行型別轉換和上面一樣,這裡的GenericArgumentValues就是沒有指定下標的
// 如:<constructor-arg value="1"/>
for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) {
if (valueHolder.isConverted()) {
resolvedValues.addGenericArgumentValue(valueHolder);
}
else {
Object resolvedValue =
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;
}
上面方法主要將 indexedArgumentValues
和 genericArgumentValues
屬性中的值通過呼叫 resolveValueIfNecessary()
方法進行解析;resolveValueIfNecessary()
方法主要解析引數的型別,比如 ref
屬性引用的 beanName
會通過 getBean()
返回例項。
建立引數陣列
ConstructorResolver#createArgumentArray
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
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] : "");
ConstructorArgumentValues.ValueHolder valueHolder = null;
if (resolvedValues != null) {
// 根據引數的下標、型別、名稱查詢是否有匹配的
valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
// 沒有匹配的 && 不是自動裝配。嘗試下一個通用的無型別引數值作為降級方法
// 它可以在型別轉換後匹配 (例如,String -> int)
if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
}
}
// 找到了匹配的valueHolder
if (valueHolder != null) {
// 新增進usedValueHolders
usedValueHolders.add(valueHolder);
Object originalValue = valueHolder.getValue();
Object convertedValue;
// 型別已經轉換過
if (valueHolder.isConverted()) {
// 獲取已經轉換過的值,作為args在paramIndex的預備引數
convertedValue = valueHolder.getConvertedValue();
args.preparedArguments[paramIndex] = convertedValue;
}
// 型別沒有轉換過
else {
// 將構造方法和引數下標封裝成MethodParameter(MethodParameter是封裝方法和引數索引的工具類)
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
try {
// 將原始值轉換為paramType型別的值,無法轉換時丟擲異常
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 = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
// 標記args需要解析
args.resolveNecessary = true;
// 將sourceValue作為args在paramIndex位置的預備引數
args.preparedArguments[paramIndex] = sourceValue;
}
}
// 將convertedValue作為args在paramIndex位置的引數
args.arguments[paramIndex] = convertedValue;
// 將originalValue作為args在paramIndex位置的原始引數
args.rawArguments[paramIndex] = originalValue;
}
// 沒有找到匹配的valueHolder
else {
// 將構造方法和引數下標封裝成MethodParameter
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
// 找不到明確的匹配,並且不是自動注入,丟擲異常
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 {
// 如果是自動注入,用resolveAutowiredArgument()解析引數,見下文詳解
// 建構函式自動注入中的引數bean就是在這邊處理
Object autowiredArgument = resolveAutowiredArgument(
methodParam, beanName, autowiredBeanNames, converter, fallback);
// 將通過自動裝配解析出來的引數賦值給args
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);
}
}
}
// 如果依賴了其他的bean,則註冊依賴關係(這邊的autowiredBeanNames,就是所有依賴的beanName)
for (String autowiredBeanName : autowiredBeanNames) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
}
// 返回解析後的引數值
return args;
}
上面方法判斷建構函式如果有匹配的引數會轉換成對應型別,如果沒有匹配的引數,多半是建構函式自動注入,通過 resolveAutowiredArgument()
去查詢 bean
並返回例項。
ConstructorResolver#resolveAutowiredArgument
protected Object resolveAutowiredArgument(MethodParameter param, String beanName, @Nullable Set<String> autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {
// 獲取引數的型別
Class<?> paramType = param.getParameterType();
// 如果引數型別是InjectionPoint
if (InjectionPoint.class.isAssignableFrom(paramType)) {
// 拿到當前的InjectionPoint(儲存了當前正在解析依賴的方法引數資訊,DependencyDescriptor)
InjectionPoint injectionPoint = currentInjectionPoint.get();
if (injectionPoint == null) {
// 當前injectionPoint為空,則丟擲異常:目前沒有可用的InjectionPoint
throw new IllegalStateException("No current InjectionPoint available for " + param);
}
// 當前injectionPoint不為空,直接返回
return injectionPoint;
}
try {
// 解析指定依賴,DependencyDescriptor:
// 將MethodParameter的方法引數索引資訊封裝成DependencyDescriptor,見下文詳解
return this.beanFactory.resolveDependency(
new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
}
// 忽略異常處理...
}
上面方法中的 resolveDependency()
方法就是解決依賴注入的關鍵所在,在分析這個方法之前我們先簡單看一下 DependencyDescriptor
類。
public class DependencyDescriptor extends InjectionPoint implements Serializable {
// 包裝依賴(屬性或者方法的某個引數)所在的宣告類
private final Class<?> declaringClass;
// 如果所包裝依賴是方法的某個引數,則這裡記錄該方法的名稱
@Nullable
private String methodName;
// 如果所包裝的是方法的某個引數,則這裡記錄該引數的型別
@Nullable
private Class<?>[] parameterTypes;
// 如果所包裝的是方法的某個引數,則這裡記錄該引數在該函式引數列表中的索引
private int parameterIndex;
// 如果所包裝的是屬性,則這裡記錄該屬性的名稱
@Nullable
private String fieldName;
// 標識所包裝依賴是否必要依賴
private final boolean required;
// 標識所包裝依賴是否需要飢餓載入
private final boolean eager;
// 標識所包裝依賴的巢狀級別
private int nestingLevel = 1;
// 標識所包裝依賴的包含者類,通常和宣告類是同一個
@Nullable
private Class<?> containingClass;
// 省略其他程式碼...
}
這個類就是依賴描述符,儲存了需要注入 bean
的型別、構造器引數的下標(構造器注入該值不為空)、是否必需、欄位名稱(欄位注入該值不為空)、方法名稱(set
方法注入該值不為空)等。
依賴解決
DefaultListableBeanFactory#resolveDependency
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// Optional型別的處理,說明Spring也可以注入Optional型別的引數
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
// ObjectFactory或ObjectProvider型別的處理
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
// javax.inject.Provider型別的處理
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
// 獲取延遲解析代理
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
// 解析依賴,返回的result為最終需要注入的bean例項,見下文詳解
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
DefaultListableBeanFactory#doResolveDependency
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// 獲取需要注入bean的快捷方式,不為空直接返回
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 獲取需要注入bean的型別
Class<?> type = descriptor.getDependencyType();
// 用於支援Spring中新增的註解@Value(確定給定的依賴項是否宣告@Value註解,如果有則拿到值)
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
// 解析MultipleBean,例如 Array,Collection,Map
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 根據型別找到匹配的bean
// matchingBeans(key: beanName value: 如果bean已經快取了例項(例如單例bean會快取其例項),
// 就是bean的例項,否則就是對應的class物件)
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
// 沒有找到匹配的bean,判斷是不是必需的,不是直接返回null,否則丟擲異常
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// 如果有多個匹配的候選者
if (matchingBeans.size() > 1) {
// 判斷最佳的候選者,也就是尋找最匹配的beanName
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
return null;
}
}
// 拿到autowiredBeanName對應的value(bean例項或bean例項型別)
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// 只找到一個符合的bean
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
// 將依賴的beanName新增到autowiredBeanNames中
autowiredBeanNames.add(autowiredBeanName);
}
// 如果需要注入的bean沒有快取例項,那麼instanceCandidate是一個Class物件,再根據getBean()去獲取對應的例項
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
// 返回最終需要注入的bean例項
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
上面方法才是真正去獲取需要注入的 bean
,大概分為以下幾個步驟:
-
檢視是否有快捷方式獲取注入
bean
是否為空,不為空直接返回。這裡的快捷方式是通過繼承DependencyDescriptor
並重寫resolveShortcut()
來實現。 -
如果引數使用
@Value
註解修飾了,如果獲取到值直接返回。 -
解析
MultipleBean
,這裡的MultipleBean
一般是Array
、Collection
、Map
這種,不為空直接返回。 -
根據型別找到所有匹配的
bean
,matchingBeans
中key
為beanName
,value
的值有兩種情況,如果bean已經快取了例項(例如單例bean會快取其例項),就是bean的例項,否則就是對應的class物件)。 -
matchingBeans
為空,判斷需要注入的bean
是否是必須的,如果是丟擲異常,否則返回null
。 -
matchingBeans
長度大於1,代表有多個候選者;選擇最佳的候選者,規則是:- 首先查詢
primary
屬性為true
的。 - 查詢優先順序最高的,實現
PriorityOrdered
介面或者標註@Priority
註解的。 - 查詢名稱匹配的。
- 首先查詢
-
只有一個候選者,直接使用。
-
如果需要注入的
bean
沒有快取例項,那麼instanceCandidate
是一個Class
物件,再根據getBean()
方法去獲取對應的例項。 -
最終返回需要注入的
bean
例項。
總結
本文主要介紹了建立 bean
例項的流程,我們可以重新梳理一下思路:
- 進行
bean
的例項化前方法回撥,如果返回非空,跳過後面步驟 - 建立
bean
的例項,如果是建構函式注入會選擇最適合的建構函式進行引數自動注入,否則呼叫預設的無參構造進行例項化bean
。
由於 doCreateBean()
方法中操作太多,這裡會分為幾篇文章,一一分析各個階段。
最後,我模仿 Spring 寫了一個精簡版,程式碼會持續更新。地址:https://github.com/leisurexi/tiny-spring。