Spring——4. Bean的載入(二)
文章目錄
Spring中Bean的載入
接著上文Spring——4. Bean的載入(一),Spring中真正去載入bean的是doCreateBean()方法;這是一個非常複雜的過程,其中很難的一點就是對於迴圈依賴的處理,所以我們先來對迴圈依賴進行了解,然後再繼續載入bean的解析。
1. Spring中的迴圈依賴
1.1 什麼是迴圈依賴
迴圈依賴就是迴圈引用,兩個或多個bean互相之間的持有對方,比如classA引用classB,
classB引用classC,classC又引用classA;最終成為一個環;
1.2 Spring中對於迴圈依賴的解決
Spring中的迴圈依賴包括:構造器迴圈依賴、setter迴圈依賴(singleton型別/prototype型別)。
首先定義三個互相引用的測試類:
public class ClassA {
private ClassB classB;
// 省略 構造器 及 set/get 方法
}
public class ClassB {
private ClassC classC;
// 省略 構造器 及 set/get 方法
}
public class ClassC {
private ClassA classA;
// 省略 構造器 及 set/get 方法
}
1.2.1 構造器迴圈依賴
表示通過構造器注入構成的迴圈依賴,這種依賴是無法解決的,只能丟擲BeanCurrentlyInCreationException 異常表示迴圈依賴。
Spring容器會將每一個正在建立bean的beanName放在一個“當前建立bean池”(singletonsCurrentlyInCreation)中,這個beanName在bean的建立過程中將一直保持在這個池中。
如果在建立bean的過程中發現自己已經在這個池裡的話,將會丟擲 BeanCurrentlyInCreationException異常表示迴圈依賴;在bean建立完成的時候將beanName從這個池中移除。
實現程式碼:
DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 省略前面部分...
beforeSingletonCreation(beanName);
// 省略後面部分...
}
return singletonObject;
}
}
protected void beforeSingletonCreation(String beanName) {
// singletonsCurrentlyInCreation 是 Set<String> 型別的
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
使用示例:
- 使用上面定義的三個測試類ClassA、ClassB、ClassC;
- 建立一個配置檔案:
constructor-circle-dependence-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="classA" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassA">
<constructor-arg name="classB" ref="classB"/>
</bean>
<bean id="classB" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassB">
<constructor-arg index="0" ref="classC"/>
</bean>
<bean id="classC" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassC">
<constructor-arg index="0" ref="classA"/>
</bean>
</beans>
- 建立一個測試方法:
private static void byConstructor() {
try {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:constructor-circle-dependence-context.xml");
} catch (Exception e) {
e.printStackTrace();
}
}
// output:
... nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'classA': Requested bean is currently in creation: Is there an unresolvable circular reference?
以上程式碼執行步驟:
- Spring容器建立“classA”的bean的時候,往singletonsCurrentlyInCreation中新增自己的beanName“classA”;然後繼續構造自己依賴的“classB”的bean;
- Spring容器建立“classB”的bean的時候,往singletonsCurrentlyInCreation中新增自己的beanName“classB”;然後繼續構造自己依賴的“classC”的bean;
- Spring容器建立“classC”的bean的時候,往singletonsCurrentlyInCreation中新增自己的beanName“classC”;然後繼續構造自己依賴的“classA”的bean;
- Spring容器又會去建立“classA”的bean,但是在往singletonsCurrentlyInCreation中新增的時候,發現新增失敗了也就是classA已經存在了,所以丟擲異常;
所以可以看到最後丟擲的BeanCurrentlyInCreationException異常;
1.2.2 setter迴圈依賴(singleton)
表示通過setter注入方式構成的迴圈依賴;對於setter造成的依賴是 通過Spring容器提前暴露
剛完成構造器注入但未完成其他步驟(如setter注入)的bean來完成的(這裡只能解決singleton型別的bean的迴圈依賴)。
通過提前暴露一個單例工廠方法,使得其他bean能夠引用到該bean:
// earlySingletonExposure 是否需要提早曝光,條件:單例 & 允許迴圈依賴 & 當前bean正在建立中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 如果需要提前曝光;
// 在bean初始化完成前將建立例項的 ObjectFactory 加入工廠
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 對bean再一次依賴引用,主要應用 SmartInstantiationAwareBeanPostProcessor
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor)bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
使用示例:
- 使用上面定義的三個測試類ClassA、ClassB、ClassC;
- 建立一個配置檔案:
setter-circle-dependence-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="classA" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassA">
<property name="classB" ref="classB"/>
</bean>
<bean id="classB" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassB">
<property name="classC" ref="classC"/>
</bean>
<bean id="classC" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassC">
<property name="classA" ref="classA"/>
</bean>
</beans>
- 建立一個測試方法:
private static void bySetter() {
try {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:setter-circle-dependence-context.xml");
} catch (Exception e) {
e.printStackTrace();
}
}
以上程式碼執行步驟:
- Spring容器建立“classA”的bean的時候,首先往singletonsCurrentlyInCreation中新增自己的beanName“classA”;
然後根據無參構造器建立一個“classA”的bean例項,並暴露一個 “ObjectFactory”的例項,用於返回一個提前暴露的 建立中的bean;然後繼續setter注入自己依賴的“classB”的bean; - Spring容器建立“classB”的bean的時候,首先往singletonsCurrentlyInCreation中新增自己的beanName“classB”;
然後根據無參構造器建立一個“classB”的bean例項,並暴露一個 “ObjectFactory”的例項,用於返回一個提前暴露的 建立中的bean;然後繼續setter注入自己依賴的“classC”的bean; - Spring容器建立“classC”的bean的時候,首先往singletonsCurrentlyInCreation中新增自己的beanName“classC”;
然後根據無參構造器建立一個“classC”的bean例項,並暴露一個 “ObjectFactory”的例項,用於返回一個提前暴露的 建立中的bean;然後繼續setter注入自己依賴的“classA”的bean; - 然後在注入“classA”的時候,由於步驟1中已經提前暴露了“ObjectFactory”的例項,並且提供實現了ObjectFactory的getObject()方法,所以可以從這個getObject()方法的具體實現方法getEarlyBeanReference()中獲取到暴露出來的正在建立中的“classA”的bean;(所以不需要再去對“classA”的bean進行注入,這樣就不會發生迴圈依賴了)
- 然後再依次注入“classB”和“classA”的bean,完成setter注入;
1.2.3 setter迴圈依賴(prototype)
對於“prototype”作用域的bean,Spring容器無法完成依賴注入,因為Spring容器不進行快取“prototype”作用域的bean,因此無法提前暴露一個建立中的bean。
使用示例:
- 使用上面定義的三個測試類ClassA、ClassB、ClassC;
- 建立一個配置檔案:
prototype-circle-dependence-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="classA" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassA" scope="prototype">
<property name="classB" ref="classB"/>
</bean>
<bean id="classB" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassB" scope="prototype">
<property name="classC" ref="classC"/>
</bean>
<bean id="classC" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassC" scope="prototype">
<property name="classA" ref="classA"/>
</bean>
</beans>
- 建立一個測試方法:
private static void byProtoType() {
try {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:prototype-circle-dependence-context.xml");
System.out.println(applicationContext);
// 注意這裡必須加 getBean() 才會觸發 bean的建立,然後丟擲異常
// 原因是在載入xml配置檔案到BeanDefinition的時候,如果是singleton型別的,會提前去獲取bean(DefaultListableBeanFactory#preInstantiateSingletons()方法中可看到)
System.out.println(applicationContext.getBean("classA"));
} catch (Exception e) {
e.printStackTrace();
}
}
// output:
... nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'classA': Requested bean is currently in creation: Is there an unresolvable circular reference?
以上程式碼的執行步驟跟setter方法注入singleton型別的bean差不多,只是不會提前暴露正在建立中的bean,所以也不會提供用於 獲取提前暴露bean的ObjectFactory。
不同點是:
上文Spring——4. Bean的載入(一)的4.1 原型模式的依賴檢查 中說到了“prototype”型別的bean在建立之前,會首先檢查prototypesCurrentlyInCreation快取中是否有對應的“beanName”,如果有則直接丟擲異常:
AbstractBeanFactory.java#doGetBean()
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null && (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}
並且在“prototype”型別的bean在執行真正建立的時候,也先往prototypesCurrentlyInCreation快取中寫入當前正在建立的beanName:
AbstractBeanFactory.java#doGetBean()
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
protected void beforePrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
}
else if (curVal instanceof String) {
Set<String> beanNameSet = new HashSet<>(2);
beanNameSet.add((String) curVal);
beanNameSet.add(beanName);
this.prototypesCurrentlyInCreation.set(beanNameSet);
}
else {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.add(beanName);
}
}
這裡由於“classA”的prototype型別的bean,在它自己建立的時候已經新增到了prototypesCurrentlyInCreation快取中,在“classC”的prototype型別的bean建立時候,需要依賴“classA”,再次去檢查的時候,就發現這個快取中已經有了,所以直接丟擲了異常。
2. 真正建立bean(doCreateBean)
在瞭解了迴圈依賴的之後,繼續來看上文Spring——4. Bean的載入(一)最後的真正建立bean;在經過了上文中 4.7.2 後處理器的應用 的resolveBeforeInstantiation()方法之後,如果沒有返回改變或者生成的bean,就需要進行常規bean的建立了。
AbstractAutowireCapableBeanFactory.java#createBean()
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 如果是單例,則先嚐試從快取中獲取beanInstance,並清除快取
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 將 BeanDefinition轉換成 BeanWrapper
// 例項化bean,根據指定bean使用對應的策略建立新的例項,如:工廠方法、建構函式主動注入、簡單初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
// 對於指定的bean,呼叫他們的 postProcessMergedBeanDefinition() 方法
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// bean合併後的處理,autowired註解通過此方法實現諸如型別的預解析
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 依賴處理
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// earlySingletonExposure 是否需要提早曝光,條件:單例 & 允許迴圈依賴 & 當前bean正在建立中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 如果需要提前曝光;
// 在bean初始化完成前將建立例項的 ObjectFactory 加入工廠
// AOP就是在這裡將advice動態織入bean中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 對bean進行填充,將各個屬性值注入,可能存在依賴於其他bean的屬性,則會遞迴初始化依賴bean
populateBean(beanName, mbd, instanceWrapper);
// 呼叫初始化方法,如 init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException)ex).getBeanName())) {
throw (BeanCreationException)ex;
} else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// 迴圈依賴檢查
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
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 " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
// Spring不但提供了對於初始化方法的擴充套件入口,統一提供了銷燬方法的擴充套件入口;
// 對於銷燬方法的擴充套件,除了配置 destroy-method方法外,還可以註冊後處理器 DestructionAwareBeanPostProcessors來統一處理bean的銷燬方法
try {
// 註冊DisposableBean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
} catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
2.1 建立bean的例項
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 解析bean class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 如果工廠方法不為空,則使用 工廠方法初始化策略
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// 一個類有多個建構函式,每個建構函式有不同的引數,呼叫前需要先根據引數鎖定建構函式或對應的工廠方法
// 採用“快取機制”,如果已經解析過了就將解析的結果新增到 RootBeanDefinition的 resolvedConstructorOrFactoryMethod屬性中;
// 不需要重複解析,直接從這個快取中取;
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);
}
2.1.1 解析class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
這裡在上文Spring——4. Bean的載入(一)的4.7 準備建立bean(createBean) 的第1小步中講解了,就是根據beanName使用反射建立出類物件Class;由於前面已經建立過了,並設定到了BeanDefinition中,所以這裡直接返回BeanDefinition中的beanClass即可:
protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)
throws CannotLoadBeanClassException {
try {
// 如果 RootBeanDefinition中本身就有beanClass,就直接返回
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
}
......
}
2.1.2 處理Supplier
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
Supplier,是JDK1.8提供的一個函式式介面,用於為建立bean的例項指定一個回撥,作為宣告式指定的工廠方法的替代方法。表示結果的提供者,如果設定了這樣的回撥函式,它將覆蓋任何其他建構函式或工廠方法後設資料。
所以這裡,如果獲取到了設定的instanceSupplier,就使用這個設定的instanceSupplier去獲取bean的例項;
2.1.3 處理factoryMethodName
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
如果在xml配置檔案中配置了 factory-method屬性,在讀取配置檔案的時候就會把這個屬性對應的methodName寫入到BeanDefinition的factoryMethodName屬性中。
所以在這裡,如果讀取到了factoryMethodName屬性,Spring就會嘗試使用instantiateUsingFactoryMethod()方法根據BeanDefinition的配置去生成bean的例項。
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
2.1.4 解析建構函式
一個bean對應的類中可能會有多個建構函式,每個建構函式的引數都不同,Spring根據引數及型別會判斷最終會使用哪個建構函式進行例項化。
但是這個判斷的過程比較複雜也比較緩慢,所以採用了快取機制,將解析過的結果新增到 resolvedConstructorOrFactoryMethod快取中。
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// 採用“快取機制”,如果已經解析過了就將解析的結果新增到 RootBeanDefinition的 resolvedConstructorOrFactoryMethod屬性中;
// 不需要重複解析,直接從這個快取中取;
if (mbd.resolvedConstructorOrFactoryMethod != null) {
// 不為空,說明已經解析過了
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
所以這裡直接判斷是否已經解析過了,如果解析過了直接把相關欄位設定為true;並且使用解析好的建構函式建立bean的例項,而不是需要再次去解析。對於bean例項的建立Spring分為了兩種情況:一種是預設建構函式的例項化,一種是帶有引數的建構函式的自動注入例項化。
if (resolved) {
// 如果已經解析過了,則使用解析好的建構函式方法
if (autowireNecessary) {
// 建構函式自動注入(帶有引數的例項化),非常複雜(主要複雜在建構函式及引數的匹配上)
return autowireConstructor(beanName, mbd, null, null);
} else {
// 使用預設建構函式構造
return instantiateBean(beanName, mbd);
}
}
2.1.4.1 autowireConstructor
protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
ConstructorResolver.java
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;
// explicitArgs是通過getBean方法傳入;Object getBean(String name, Object... args)
// 如果傳入引數explicitArgs不為空,則可以確定建構函式引數就是它;
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
// 如果getBean的時候沒有指定引數,則嘗試先從快取中獲取
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;
}
}
}
// 如果快取中存在
if (argsToResolve != null) {
// 快取中的值可能是原始值也可能是最終值
// 型別轉換器的過濾,如果給定方法的建構函式 A(int, int),通過此方法把配置中的("1","1") 轉換為 (1,1)
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];
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();
// 有了配置的引數資訊,就可以獲取對應的引數值資訊(使用resolveConstructorArguments處理),並返回解析到的引數的個數
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// 排序給定的建構函式(排序演算法:1. public建構函式優先;2. 引數數量降序)
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) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
if (parameterCount < minNrOfArgs) {
continue;
}
ArgumentsHolder argsHolder;
Class<?>[] paramTypes = candidate.getParameterTypes();
if (resolvedValues != null) {
// 有引數則根據值構造對應引數型別的引數
try {
// 由於在配置檔案中並不是限制只能使用引數索引的方式去建立,還支援指定引數名稱進行設定引數值;如 <constructor-arg name="classB" ref="classB"/>
// 所以這種情況下,就需要首先確定建構函式中的引數名稱;獲取引數名稱有兩種方式:註解、ParameterNameDiscoverer
// 通過註解獲取引數名稱
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
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 {
// 建構函式沒有引數的情況,直接使用getBean方法指定的引數,建立引數持有者
// Explicit arguments given -> arguments length must match exactly.
if (parameterCount != 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");
// 根據例項化策略,以及得到的 建構函式 和 建構函式引數 例項化bean;
Object beanInstance = instantiate(beanName, mbd, constructorToUse, argsToUse);
bw.setBeanInstance(beanInstance);
return bw;
}
這個方法邏輯很複雜,程式碼量也很大,感覺不太符合Spring一貫的編碼風格…下面就來一步一步地分析這個方法中的內容:
- 建構函式引數的確定:
-
根據explicitArgs判斷:
// explicitArgs是通過getBean方法傳入;Object getBean(String name, Object... args) // 如果傳入引數explicitArgs不為空,則可以確定建構函式引數就是它; if (explicitArgs != null) { argsToUse = explicitArgs; }
如果getBean時傳入的引數explicitArgs不為空,則直接可以確定要使用的建構函式的引數就是這個傳入的引數;
-
從快取中獲取:
else { // 如果getBean的時候沒有指定引數,則嘗試從先快取中獲取 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; } } } // 如果快取中存在解析了部分的引數,就需要去轉換 if (argsToResolve != null) { argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true); } }
如果沒有傳入explicitArgs引數,則先嚐試從快取中去獲取引數;這裡有個區別就是解析完成的構造器引數和解析了部分的構造器引數。
因為在快取中快取的可能是引數的最終型別(解析完成的),也可能是引數的初始型別,例如:建構函式要求的是int型別,但是初始型別是String。所以需要經過型別轉換器的過濾以確保引數型別和建構函式引數型別對應。
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 = argsToResolve[argIndex]; MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex); if (argValue == autowiredArgumentMarker) { argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, fallback); } else if (argValue instanceof BeanMetadataElement) { argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue); } else if (argValue instanceof String) { argValue = 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; }
-
從配置檔案中獲取:
如果沒有傳入explicitArgs引數也無法在快取中獲取到引數,就只有從配置檔案中獲取配置的建構函式的引數了。
經過之前的分析,我們知道了Spring中的配置檔案的資訊都會被封裝到BeanDefinition的例項中,也就是引數mbd中;所以我們可以通過 mbd.getConstructorArgumentValues()方法獲取到配置檔案中的資訊,有了配置檔案中的資訊,就可以獲取到引數值的資訊,並且獲取解析到的引數的個數:// 獲取配置檔案中的配置的建構函式引數資訊 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); // 用於承載解析後的,建構函式引數的值 resolvedValues = new ConstructorArgumentValues(); // 有了配置的引數資訊,就可以獲取對應的引數值資訊(使用resolveConstructorArguments處理),並返回解析到的引數的個數 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
只是這個部分放在了下面和 建構函式的確定 一起了。
-
- 建構函式的確定(當建構函式為空,或者建構函式引數為空):
- 判斷是否有傳過來的建構函式,如果沒有傳過來就進行處理:
如果沒有傳過來就從BeanDefinition的beanClass物件中去獲取;// 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); } }
- 可能是預設建構函式的處理:
如果建構函式只有一個;並且沒有建構函式引數;也沒有建構函式引數的值,說明就是隻有一個預設的建構函式,則可以直接進行 instantiate例項化bean。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; } }
- 確定建構函式引數,及引數的最小個數:
如果傳過來了建構函式引數,則最小的引數個數肯定是傳過來的引數個數;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(); // 有了配置的引數資訊,就可以獲取對應的引數值資訊(使用resolveConstructorArguments處理),並返回解析到的引數的個數 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); }
如果沒有傳過來,並且到了這個步驟的肯定是沒有從快取中獲取到建構函式引數的;所以這裡就去配置檔案中讀取配置的建構函式引數的資訊;讀取到後進行解析建構函式引數並封裝到 resolvedValues中,並且返回引數的最小個數。 - 確定建構函式:
在已經確定了建構函式引數之後,接下來就應該根據建構函式引數在所有的建構函式中鎖定對應的建構函式。
匹配的方法就是根據引數個數進行匹配,所以在匹配之前需要先對建構函式進行排序,排序規則:public優先,引數數量降序;非public其次,引數數量降序。
由於在配置檔案中並不是唯一限制使用引數位置索引去建立構造器引數,還支援使用指定引數名稱的方式,所以需要首先確定建構函式中引數名稱;這裡就需要進行轉換響應的引數型別:AutowireUtils.sortConstructors(candidates);
for (Constructor<?> candidate : candidates) { // 獲取引數數量 int parameterCount = candidate.getParameterCount(); if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) { // Already found greedy constructor that can be satisfied -> // do not look any further, there are only less greedy constructors left. break; } if (parameterCount < minNrOfArgs) { continue; } ArgumentsHolder argsHolder; Class<?>[] paramTypes = candidate.getParameterTypes(); if (resolvedValues != null) { // 有引數則根據值構造對應引數型別的引數 try { // 由於在配置檔案中並不是限制只能使用引數索引的方式去建立,還支援指定引數名稱進行設定引數值;如 <constructor-arg name="classB" ref="classB"/> // 所以這種情況下,就需要首先確定建構函式中的引數名稱;獲取引數名稱有兩種方式:註解、ParameterNameDiscoverer // 通過註解獲取引數名稱 String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount); 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 { // 建構函式沒有引數的情況,直接使用getBean方法指定的引數,建立引數持有者 // Explicit arguments given -> arguments length must match exactly. if (parameterCount != 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); } }
- 判斷是否有傳過來的建構函式,如果沒有傳過來就進行處理:
- 根據例項化策略以及得到的建構函式及建構函式引數例項化bean:
這裡的根據策略例項化bean後面一點再解析。// 根據例項化策略,以及得到的 建構函式 和 建構函式引數 例項化bean; Object beanInstance = instantiate(beanName, mbd, constructorToUse, argsToUse); bw.setBeanInstance(beanInstance); private Object instantiate( String beanName, RootBeanDefinition mbd, Constructor<?> constructorToUse, Object[] argsToUse) { try { InstantiationStrategy strategy = this.beanFactory.getInstantiationStrategy(); if (System.getSecurityManager() != null) { return AccessController.doPrivileged((PrivilegedAction<Object>) () -> strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse), this.beanFactory.getAccessControlContext()); } else { return strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse); } } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean instantiation via constructor failed", ex); } }
2.1.4.2 instantiateBean
經歷了帶引數的建構函式的例項化,再來看不帶引數的建構函式的例項化過程應該會覺得很簡單了:
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(
(PrivilegedAction<Object>)() -> getInstantiationStrategy().instantiate(mbd, beanName, this),
getAccessControlContext());
} else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
} catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
因為帶引數的建構函式的例項化過程中,主要精力都是放在了建構函式引數以及建構函式的確定上;所以沒有引數的例項化過程,就是直接根據例項化策略進行例項化就行了。
2.1.4.3 不同例項化策略 -> 例項化bean
其實經過前面的解析,已經得到了足夠例項化的所有相關資訊,完全可以使用最簡單的反射就可以構造例項物件;但是為什麼Spring為什麼要採用不同的例項化策略來構造物件呢?
InstantiationStrategy.java
Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) throws BeansException;
SimpleInstantiationStrategy.java
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
// 如果沒有覆蓋或者動態替換的方法,直接使用反射
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);
}
// 如果有需要覆蓋或者動態替換的方法,需要使用cglib進行動態代理,因為可以在建立代理的同時將動態方法織入類中
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy");
}
CglibSubclassingInstantiationStrategy.java
public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
if (ctor == null) {
instance = BeanUtils.instantiateClass(subclass);
}
else {
try {
Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
instance = enhancedSubclassConstructor.newInstance(args);
}
catch (Exception ex) {
throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
}
}
// SPR-10785: set callbacks directly on the instance instead of in the
// enhanced class (via the Enhancer) in order to avoid memory leaks.
Factory factory = (Factory) instance;
factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
return instance;
}
從上面兩個方法我們可以得到答案:
- 如果 (!bd.hasMethodOverrides())成立,也就是沒有使用lookup-method或者replace-method方法,那麼直接使用反射的方式就可以構造例項物件了;
- 如果使用了這兩個特性,就需要將這兩個配置提供的功能切入進去,所以必須要用到動態代理的方式將包含兩個特性所對應的邏輯的 攔截增強器設定進去,這樣才可以保證在呼叫方法的時候會被響應的攔截器增強,返回值會包含攔截器的代理例項。
2.2 依賴處理
在獲取到bean例項之後,首先會將MergedBeanDefinitionPostProcessors應用到指定的bean定義上(主要是呼叫它們的postProcessMergedBeanDefinition()方法)。然後就該對於bean的依賴進行處理了,也就是Spring中迴圈依賴的解決。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 如果需要提前曝光;
// 在bean初始化完成前將建立例項的 ObjectFactory 加入工廠
// AOP就是在這裡將advice動態織入bean中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
- earlySingletonExposure:是否是單例、是否允許迴圈依賴、是否對應的bean正在建立;三個條件的綜合,當這三個條件都滿足時,才會執行addSingletonFactory操作;
- allowCircularReferences:並沒有在配置檔案中找到如果配置這個屬性,不過可以通過獲取ApplicationContext的時候進行設定:
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:setter-circle-dependence-context.xml"); applicationContext.setAllowCircularReferences(false);
- isSingletonCurrentlyInCreation(beanName):當前bean是否在建立中;
- Spring中使用了 DefaultSingletonBeanRegistry的 singletonsCurrentlyInCreation屬性來記錄bean的載入狀態;
- 在bean建立之前會將beanName記錄在這個屬性中,在bean建立結束後會將beanName從屬性中移除;
在上文Spring——4. Bean的載入(一)的 4.6.1 singleton型別bean的建立 中:- bean建立之前,呼叫了 beforeSingletonCreation(beanName)方法,記錄了當前beanName正在建立的狀態到 singletonsCurrentlyInCreation屬性中:
beforeSingletonCreation(beanName); protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
- bean建立之後(在當前整個createBean()完成之後),呼叫了 afterSingletonCreation(beanName)方法,移除記錄在 singletonsCurrentlyInCreation屬性中的beanName:
afterSingletonCreation(beanName); protected void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } }
- bean建立之前,呼叫了 beforeSingletonCreation(beanName)方法,記錄了當前beanName正在建立的狀態到 singletonsCurrentlyInCreation屬性中:
示例:
以簡單的AB迴圈依賴為例,類A中含有屬性類B,類B中又會含有屬性類A;Spring對這種情況下的迴圈依賴處理如下:
裡面相關方法的具體實現程式碼在上面文章中都能找到,結合起來應該就能看明白了,這也就是Spring解決迴圈依賴的具體實現。
2.3 屬性注入
在上面說到的解決迴圈依賴的過程中已經提到了填充屬性,也就是populateBean()方法:
AbstractAutowireCapableBeanFactory.java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
} else {
// Skip property population phase for null instance.
return;
}
}
// 給 InstantiationAwareBeanPostProcessors 最後一次機會在屬性設定前來改變bean的狀態;
// 如:可以用來支援屬性注入的型別
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// BeanDefinition不是自定義的,並且已經註冊了 InstantiationAwareBeanPostProcessors
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
// postProcessAfterInstantiation 可以控制是否繼續進行屬性填充
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
// 如果後置處理器判斷出不進行屬性填充,直接返回
return;
}
}
}
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// 根據名稱自動注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 根據型別自定注入
autowireByType(beanName, mbd, bw, newPvs);
}
// 提取依賴的bean,並統一存入 PropertyValues
pvs = newPvs;
}
// 後置處理器已經初始化
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 需要依賴檢查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 對所有需要依賴檢查的屬性 進行後置處理
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 依賴檢查,對應depends-on屬性
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
// 將所有PropertyValues中的屬性填充至 BeanWrapper中
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
主要步驟:
- 如果註冊了 InstantiationAwareBeanPostProcessors,則應用 InstantiationAwareBeanPostProcessor處理的 postProcessAfterInstantiation()方法,控制程式是否還要繼續屬性填充;
- 根據不同的注入型別(byName/byType)進行注入,並且提取依賴的bean,並統一存入 PropertyValues;
- 如果註冊了 InstantiationAwareBeanPostProcessors,則應用 InstantiationAwareBeanPostProcessor處理的 postProcessProperties()方法,對屬性獲取完畢填充前對屬性的再次處理;(典型應用是 RequiredAnnotationBeanPostProcessor 類中對屬性的驗證)
- 如果需要依賴檢查的話,進行依賴檢查;
- 將所有PropertyValues中的屬性填充至 BeanWrapper中;
這裡重點講一下依賴注入及屬性填充,在講依賴注入之前,先講講Spring中自動裝配(autowire)的幾種模式。
2.3.1 autowire
在Spring中,autowire有5中模式:
- no(預設):
對應原始碼的 int AUTOWIRE_NO = 0; Spring預設的是不進行自動裝配,通過手工設定ref來進行裝配bean;示例:<bean id="classA" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassA"> <property name="classB" ref="classB"/> </bean> <bean id="classB" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassB"> <property name="classC" ref="classC"/> </bean>
- byName:
對應原始碼的 int AUTOWIRE_BY_NAME = 1; 通過引數的名字進行裝配bean;如果當前bean要裝配的bean的property 和另外一個bean的name相同,就進行裝配;示例:<bean id="classA" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassA" autowire="byName"> </bean> <bean id="classB" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassB" autowire="byName"> </bean>
- byType:
對應原始碼的 int AUTOWIRE_BY_TYPE = 2; 通過引數的資料型別進行裝配bean;如果當前bean要裝配的bean的資料型別和另外一個bean的相同,就進行裝配;示例:<bean id="classA" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassA" autowire="byType"> </bean> <bean id="classB" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassB" autowire="byType"> </bean>
- construct:
對應原始碼的 int AUTOWIRE_CONSTRUCTOR = 3; 構造方法的引數通過byType的形式自動裝配;示例:<bean id="classA" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassA" autowire="constructor"> </bean> <bean id="classB" class="org.bgy.spring.study.spring.bean.definition.circle.dependence.ClassB" autowire="constructor"> </bean>
- default:
由上級標籤的default-autowire屬性確定;
2.3.2 autowireByName
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
// 根據名稱自動注入
autowireByName(beanName, mbd, bw, newPvs);
}
protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 獲取bw中需要依賴注入的屬性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
// 遞迴初始化相關的bean
Object bean = getBean(propertyName);
// 加入到PropertyValues中
pvs.add(propertyName, bean);
// 註冊依賴
registerDependentBean(propertyName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("Added autowiring by name from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
} else {
if (logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName + "' by name: no matching bean found");
}
}
}
}
這裡首先獲取到當前bean中需要依賴注入的屬性propertyNames,並且遍歷這個propertyNames判斷每個propertyName,如果包含了bean,就遞迴初始化這個需要依賴的bean;最後再加入到 PropertyValues中。
2.3.3 autowireByType
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 根據型別自定注入
autowireByType(beanName, mbd, bw, newPvs);
}
protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
// 獲取需要依賴注入的屬性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// Don't try autowiring by type for type Object: never makes sense,
// even if it technically is a unsatisfied, non-simple property.
if (Object.class != pd.getPropertyType()) {
// 探測指定屬性的set方法
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
// 是否緊急(有優先順序的情況下不允許緊急初始化)
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 解析指定beanName的屬性所匹配的值,並把解析到的屬性名稱儲存在 autowiredBeanNames中;
// 當屬性存在多個封裝bean時(@Autowired private List<A> aList),將會找到所有匹配A型別的bean將將其注入
// resolveDependency 尋找型別匹配的邏輯
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
// 加入到PropertyValues中
pvs.add(propertyName, autowiredArgument);
}
// 新建了區域性遍歷 autowiredBeanNames,用於儲存所有依賴的bean(如果只是對非集合類的屬性注入,這裡無效)
for (String autowiredBeanName : autowiredBeanNames) {
// 註冊依賴
registerDependentBean(autowiredBeanName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
autowiredBeanNames.clear();
}
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
這裡首先獲取到當前bean中需要依賴注入的屬性propertyNames,並且遍歷這個propertyNames的每一個propertyName:
- 把這個propertyName轉換成PropertyDescriptor的例項pd,這個例項中會包含:當前bean的Class型別 和property屬性的type、set/get方法、name等;
- 從pd中獲取到需要注入的property屬性的set方法的MethodParameter的例項 methodParam;
- 獲取優先順序eager,並且使用 methodParam和eager一起生成 DependencyDescriptor的例項desc;
- 尋找型別匹配的bean;
- 最後再加入到 PropertyValues中;
這裡最複雜的就是尋找型別匹配的bean:
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
DefaultListableBeanFactory.java
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) {
// Optional 類注入的特殊處理
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
// ObjectFactory 類注入的特殊處理
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
// javaxInjectProviderClass 類注入的特殊處理
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
// 通用處理邏輯
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType();
// 用於支援註解 @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) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
// 如果解析器沒有解析成功,需要考慮各種情況
// 解析多個bean
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 根據屬性型別找到BeanFactory中所有型別的匹配bean;
// 返回值的結構為:key = 匹配的beanName,value = beanName對應的例項化後的bean(通過getBean(beanName)返回)
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
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());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
這裡的resolveCandidate()方法,會去遞迴呼叫beanFactory的getBean()方法初始化依賴的bean:
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName);
}
也就跟前面的autowireByName()方法的這裡一樣。
2.3.4 applyPropertyValues
程式執行到這裡,已經完成了對所有注入屬性的獲取,但是獲取的屬性是以PropertyValues形式存在的,還沒有應用到已經例項化的bean中,應用的工作是在applyPropertyValues()方法中:
if (pvs != null) {
// 將所有PropertyValues中的屬性填充至 BeanWrapper中
applyPropertyValues(beanName, mbd, bw, pvs);
}
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs.isEmpty()) {
return;
}
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl)bw).setSecurityContext(getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues)pvs;
// 如果mpvs中的值已經被轉換為對應的型別,那麼可以直接設定到beanWrapper中;
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
// 把屬性應用到beanWrapper中
bw.setPropertyValues(mpvs);
return;
} catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
} else {
// 如果pvs並不是使用 MutablePropertyValues封裝的型別,那麼直接使用原始的屬性獲取方法
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
// 獲取對應的解析器
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
// 遍歷屬性,將屬性轉換為對應類的對應屬性的型別
for (PropertyValue pv : original) {
if (pv.isConverted()) {
// 如果轉換過了,直接新增
deepCopy.add(pv);
} else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
if (originalValue == AutowiredPropertyMarker.INSTANCE) {
Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
if (writeMethod == null) {
throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
}
originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
}
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
} else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue)originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
} else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
// 處理完成後,把屬性應用到beanWrapper中
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
} catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
2.4 初始化bean
在前面,我們已經做了對bean的例項化,並且進行了屬性的填充;這個時候,才會對bean進行初始化,程式碼實現:
exposedObject = initializeBean(beanName, exposedObject, mbd);
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>)() -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
} else {
// 對特殊的bean處理:Aware、BeanClassLoaderAware、BeanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 使用者對Spring的擴充套件的地方
// 在呼叫自定義初始化方法前,呼叫 BeanPostProcessor 的 postProcessBeforeInitialization() 方法,對業務需求進行相應的處理
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 使用者自定義的初始化方法有兩種:
// 1. 配置 init-method 方法;
// 2. 使自定義的bean 實現 InitializingBean介面,並在 afterPropertiesSet() 中實現自己的初始化業務邏輯
// 呼叫使用者自定義的init方法(實現上面兩種自定義初始化方法的呼叫)
invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 在呼叫自定義初始化方法後,呼叫 BeanPostProcessor 的 postProcessAfterInitialization() 方法,對業務需求進行相應的處理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
在初始化bean的過程中,有以下幾個主要步驟:
2.4.1 呼叫 Aware方法
在分析原始碼之前,先來了解一下Aware介面的使用。
Spring中提供了很多Aware介面,比如:BeanFactoryAware、ApplicationContextAware、ResourceLoaderAware、ServletContextAware等。
作用:實現了這些Aware介面的bean,在被初始化之後,會被注入一些相對應的資源;比如:實現了BeanFactoryAware的bean在被初始化之後,Spring容器將會注入BeanFactory的例項;實現了ApplicationContextAware的bean在被初始化之後會,Spring容器將會注入ApplicationContext的例項等。
示例程式碼:
- 先建立一個普通的bean:
public class Hello {
public void say() {
System.out.println("hello");
}
}
- 建立一個實現了Aware介面的 BeanFactoryAwareDemo的bean:
public class BeanFactoryAwareDemo implements BeanFactoryAware {
private BeanFactory beanFactory;
/**
* 宣告bean的時候,Spring會自動注入BeanFactory
* @param beanFactory
* @throws BeansException
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
public void testAware() {
// 這裡使用Spring主動注入的beanFactory來獲取hello的bean
Hello hello = (Hello)beanFactory.getBean("hello");
hello.say();
}
}
- 建立xml配置檔案:
aware-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="org.bgy.spring.study.spring.bean.definition.aware.Hello"/>
<bean id="beanFactoryAwareDemo" class="org.bgy.spring.study.spring.bean.definition.aware.BeanFactoryAwareDemo"/>
</beans>
- 建立一個測試類:
public class BeanFactoryAwareTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:aware-context.xml");
BeanFactoryAwareDemo beanFactoryAwareDemo = (BeanFactoryAwareDemo)applicationContext.getBean("beanFactoryAwareDemo");
beanFactoryAwareDemo.testAware();
}
}
// output:
hello
回到程式碼:
invokeAwareMethods(beanName, bean);
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware)bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware)bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
程式碼主要就是對於不同的Aware型別,設定不同的屬性值(資源)。
2.4.2 後置處理器的應用
2.4.2.1 BeanPostProcessor
BeanPostProcessor是Spring開放式架構中必不可少的一個亮點,可以給使用者充足的許可權去更改或者擴充套件Spring。
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
postProcessBeforeInitialization()執行時機:例項化方法執行之後,init()方法執行之前;
postProcessAfterInitialization() 執行時機:init()方法執行之後;
這裡返回的都是bean;
作用:
通過實現這個介面,使用者可以對Spring管理的bean在初始化之前或者初始化之後,實現一些自定義的邏輯處理;其實也就是對Bean的一種增強。
回到程式碼,對於BeanPostProcessor的註冊是在其他地方完成的,這裡其實就是應用 BeanPostProcessor的地方了:
- 在呼叫使用者自定義初始化方法前會呼叫postProcessBeforeInitialization()方法:
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
- 在呼叫使用者自定義初始化方法後會呼叫postProcessAfterInitialization()方法:
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
這兩個地方返回的都是呼叫了 BeanPostProcessor介面的兩個方法之後,被增強了的wrappedBean。
2.4.3 呼叫自定義的初始化方法
在bean的配置中,有一個 init-method 的屬性;這個屬性的作用是在bean載入完成之前,呼叫init-method指定的方法來根據使用者業務指定的初始化方法對bean進行相應的初始化。
使用者自定義的初始化方法除了使用配置的 init-method之外,還可以使用自定義的bean實現 InitializingBean介面,並在 afterPropertiesSet()方法中實現自己的初始化邏輯。
init-method和 afterPropertiesSet都是在初始化bean時呼叫 invokeInitMethods()方法的時候執行的,執行順序是 afterPropertiesSet先執行,init-method後執行。
invokeInitMethods(beanName, wrappedBean, mbd);
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
// 如果是 InitializingBean,就需要呼叫 afterPropertiesSet()方法
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>)() -> {
((InitializingBean)bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
} else {
// 呼叫afterPropertiesSet
((InitializingBean)bean).afterPropertiesSet();
}
}
// 不是 InitializingBean
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 呼叫自定義初始化方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
在這裡,如果不是 InitializingBean,即是init-method方法,就呼叫自定義方法進行初始化:
protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd)
throws Throwable {
String initMethodName = mbd.getInitMethodName();
Assert.state(initMethodName != null, "No init method set");
Method initMethod = (mbd.isNonPublicAccessAllowed() ?
BeanUtils.findMethod(bean.getClass(), initMethodName) :
ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
if (initMethod == null) {
if (mbd.isEnforceInitMethod()) {
throw new BeanDefinitionValidationException("Could not find an init method named '" +
initMethodName + "' on bean with name '" + beanName + "'");
} else {
if (logger.isTraceEnabled()) {
logger.trace("No default init method named '" + initMethodName +
"' found on bean with name '" + beanName + "'");
}
// Ignore non-existent default lifecycle methods.
return;
}
}
if (logger.isTraceEnabled()) {
logger.trace("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'");
}
Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod);
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>)() -> {
ReflectionUtils.makeAccessible(methodToInvoke);
return null;
});
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>)
() -> methodToInvoke.invoke(bean), getAccessControlContext());
} catch (PrivilegedActionException pae) {
InvocationTargetException ex = (InvocationTargetException)pae.getException();
throw ex.getTargetException();
}
} else {
try {
ReflectionUtils.makeAccessible(methodToInvoke);
methodToInvoke.invoke(bean);
} catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
這個實現也比較簡單,先從RootBeanDefinition中獲取到 init-method中的指定的初始化方法的名稱 initMethodName,然後使用反射獲取到方法的Method,再使用反射呼叫就行了。
2.5 再次檢查迴圈依賴
在這裡會再次檢測已經載入的bean是否已經出現了迴圈依賴,並判斷是否需要丟擲異常(但是我自己經過除錯,好像沒有找到什麼情況會走到這一步才檢測出來迴圈依賴的…):
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
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 " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
2.6 註冊DisposableBean
Spring中不但提供了對於初始化方法的擴充套件入口,還提供了對於銷燬方法的擴充套件入口;對於銷燬方法的擴充套件,除了xml的配置屬性 destroy-method之外,還可以通過註冊後處理器 DestructionAwareBeanPostProcessor來統一處理bean的銷燬方法:
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
// 單例模式下注冊需要銷燬的bean,此方法中會處理實現 DisposableBean的bean,並且對所有的bean使用 DestructionAwareBeanPostProcessors處理
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// 自定義 scope的處理
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
在這裡首先判斷是否需要進行自定義銷燬bean:
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
return (bean.getClass() != NullBean.class &&
(DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() &&
DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors()))));
}
判斷需要銷燬成立的主要條件是:指定了destroy-method方法,或者註冊了 DestructionAwareBeanPostProcessor後處理器。
在判斷到需要自定義銷燬bean之後,就根據bean的不同模式進行處理。
到這裡,Spring中bean的載入流程就分析完畢了。
3. 整體流程思維導圖
最後附上一個整體流程的思維導圖:Spring Bean載入體系,本篇文章對應其中的 自定義標籤的解析 部分。
相關文章
- Spring原始碼之Bean的載入(二)Spring原始碼Bean
- Spring容器 —— 深入 bean 的載入(五、初始化 bean)SpringBean
- Spring原始碼之Bean的載入(四)Spring原始碼Bean
- Spring原始碼之Bean的載入(三)Spring原始碼Bean
- Spring原始碼之Bean的載入(一)Spring原始碼Bean
- Spring如何控制Bean的載入順序SpringBean
- spring bean定義與載入方式SpringBean
- spring註解@lazy,bean懶載入SpringBean
- spring原始碼閱讀筆記08:bean載入之建立beanSpring原始碼筆記Bean
- Spring入門(二):自動化裝配beanSpringBean
- 死磕Spring之IoC篇 - 開啟 Bean 的載入SpringBean
- Spring原始碼之Bean的載入(五) populateBean 和 DisposableBeanSpring原始碼Bean
- 二、Spring裝配BeanSpringBean
- Spring裝配Bean(二)SpringBean
- Spring解密 – Bean的載入流程Spring解密Bean
- spring原始碼深度解析— IOC 之 開啟 bean 的載入Spring原始碼Bean
- 初識Spring —— Bean的裝配(二)SpringBean
- 多重載入Bean方式Bean
- spring心得1--spring入門介紹@bean的載入初講@第一個spring專案helloWordSpringBean
- Spring原始碼:Bean的生命週期(二)Spring原始碼Bean
- Spring學習(二)Bean 作用域SpringBean
- 徹底搞懂Bean載入Bean
- Spring入門(六):條件化的beanSpringBean
- Spring原始碼解析-applicationContext.xml載入和bean的註冊Spring原始碼APPContextXMLBean
- Spring框架系列(二)之Bean的註解管理Spring框架Bean
- Spring學習之——Bean載入流程SpringBean
- Spring中Bean及@Bean的理解SpringBean
- Spring原始碼剖析4:懶載入的單例Bean獲取過程分析Spring原始碼單例Bean
- Spring原始碼系列(二)--bean元件的原始碼分析Spring原始碼Bean元件
- Spring中的BeanSpringBean
- 【Spring原始碼分析】非懶載入的單例Bean初始化過程(下篇)Spring原始碼單例Bean
- 【Spring原始碼分析】非懶載入的單例Bean初始化過程(上篇)Spring原始碼單例Bean
- [Spring]BeanSpringBean
- Spring裝配Bean(六)Bean的作用域SpringBean
- spring自動裝配與spring_bean之間的關係(二)SpringBean
- Spring學習(二):3個裝配bean方式SpringBean
- 4. Spring對IoC的實現Spring
- Spring Bean Scope 有狀態的Bean和無狀態的BeanSpringBean