該系列文章是本人在學習 Spring 的過程中總結下來的,里面涉及到相關源碼,可能對讀者不太友好,請結合我的源碼注釋 Spring 源碼分析 GitHub 地址 進行閱讀
Spring 版本:5.1.14.RELEASE
開始閱讀這一系列文章之前,建議先查看《深入了解 Spring IoC(面試題)》這一篇文章
該系列其他文章請查看:《死磕 Spring 之 IoC 篇 - 文章導讀》
Bean 的屬性填充階段
當我們顯示或者隱式地調用AbstractBeanFactory 的 getBean(...) 方法時,會觸發 Bean 的加載,在《開啟 Bean 的加載》文章中分析了整個加載過程。
對於不同作用域的 Bean,底層都會調用 AbstractAutowireCapableBeanFactory 的 createBean(...) 方法進行創建,在《Bean 的創建過程》文章中分析了整個創建過程。創建 Bean 的過程中,在獲取到的一個實例對象后,里面的相關屬性也許是空的,那么接下來要做的就是將需要填充的屬性進行依賴注入,然后再進行后續的初始化工作。整個的屬性填充過程非常復雜,因為配置的屬性值可能是一個表達式,需要解析,類型也可能不對,需要進行類型轉換,還可能是一個對象,需要找到對應的 Bean 然后注入(依賴注入),存在有各種處理,本文將會分析創建 Bean 過程中的屬性填充階段。
回顧
先來回顧一下創建 Bean 過程中屬性填充階段對應的代碼:
// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Initialize the bean instance.
// 開始初始化 `bean`
Object exposedObject = bean;
try {
// <4> 對 `bean` 進行屬性填充,注入對應的屬性值
populateBean(beanName, mbd, instanceWrapper);
// <5> 初始化這個 `exposedObject`,調用其初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
在創建好實例對象后,這個對象的屬性還沒有賦值,所以將這個實例對象的相關屬性進行賦值,也就是上面的第 <4> 步
開啟 Bean 的屬性填充
populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) 方法,屬性填充,如下:
// AbstractAutowireCapableBeanFactory.java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// <1> 如果實例對象為空,則進行下面的判斷
if (bw == null) {
// <1.1> 這個 Bean 有屬性,則拋出異常
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
// <1.2> 否則,不用屬性填充,直接 `return`
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
// <2> 實例化階段的后置處理,如果滿足這兩個條件
if (!mbd.isSynthetic() // RootBeanDefinition 不是用戶定義的(由 Spring 解析出來的)
&& hasInstantiationAwareBeanPostProcessors()) { // 是否有 InstantiationAwareBeanPostProcessor 處理器
// <2.1> 遍歷所有的 BeanPostProcessor
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 如果為 InstantiationAwareBeanPostProcessor 類型
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// <2.2> 對實例化對象進行后置處理
// 注意如果返回 false,直接 `return`,不會調用后面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
// <3> 獲取 `pvs`,承載當前對象的屬性值
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// <4> 獲取這個 Bean 的注入模式,默認為 **AUTOWIRE_NO**,例如可以通過 `@Bean` 注解的 `autowire` 屬性配置注入模式
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// <4.1> 如果注入模式為 **AUTOWIRE_BY_NAME** 或者 **AUTOWIRE_BY_TYPE**,則通過下面的方式獲取屬性值
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// <4.2> 將 `pvs` 封裝成 MutablePropertyValues 對象 `newPvs`(允許對屬性進行相關操作)
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// <4.3> **AUTOWIRE_BY_NAME** 模式,通過名稱獲取相關屬性值,保存在 `newPvs` 中
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// <4.4> **AUTOWIRE_BY_TYPE** 模式,通過類型獲取相關屬性值,保存在 `newPvs` 中
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
// <4.5> 將 `newPvs` 復制給 `pvs`
pvs = newPvs;
}
// 是否有 InstantiationAwareBeanPostProcessor 處理器
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否需要進行依賴檢查,默認為 true
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
// <5> 通過 InstantiationAwareBeanPostProcessor 處理器(如果有)對 `pvs` 進行處理
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// <5.1> 遍歷所有的 BeanPostProcessor
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 如果為 InstantiationAwareBeanPostProcessor 類型
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
/**
* Spring 內部的 InstantiationAwareBeanPostProcessor 處理器:
* {@link AutowiredAnnotationBeanPostProcessor#postProcessProperties} 會解析 @Autowired 和 @Value 注解標注的屬性,獲取對應屬性值;
* {@link org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessProperties} 會解析 @Resource 注解標注的屬性,獲取對應的屬性值
*/
// <5.2> 調用處理器的 `postProcessProperties(...)` 方法,對 `pvs` 進行后置處理
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// <5.3> 如果上一步的處理結果為空,可能是新版本導致的(Spring 5.1 之前沒有上面這個方法),則需要兼容老版本
if (pvsToUse == null) {
// <5.3.1> 找到這個 Bean 的所有 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有信息)
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// <5.3.2> 調用處理器的 `postProcessPropertyValues(...)` 方法,對 `pvs` 進行后置處理
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
// <5.3.3> 如果處理后的 PropertyValues 對象為空,直接 `return`,則不會調用后面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充
if (pvsToUse == null) {
return;
}
}
// <5.4> 將處理后的 `pvsToUse` 復制給 `pvs`
pvs = pvsToUse;
}
}
}
// <6> 依賴檢查
if (needsDepCheck) {
// <6.1> 找到這個 Bean 的所有 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有信息)
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// <6.2> 依賴檢查,如果沒有找到對應的屬性值,則根據檢查策略進行拋出異常(默認不會)
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// <7> 如果 `pvs` 不為空,則將里面的屬性值設置到當前 Bean 對應的屬性中(依賴注入)
// 前面找到的屬性值並沒有設置到 Bean 中,且屬性值可能是一個表達式,類型也可能也不對,需要先進行處理和類型轉換,然后再設置到該實例對象中
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
過程大致如下:
-
如果實例對象為
null,則進行下面的判斷- 這個 Bean 有屬性,則拋出異常
- 否則,不用屬性填充,直接
return
-
實例化階段的后置處理,如果滿足這兩個條件:RootBeanDefinition 不是用戶定義的(由 Spring 解析出來的)、是否有 InstantiationAwareBeanPostProcessor 處理器
-
遍歷所有的 BeanPostProcessor
-
如果為 InstantiationAwareBeanPostProcessor 類型,則對實例化對象進行后置處理
注意,如果返回 false,直接
return,不會調用后面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充
-
-
獲取
pvs,承載當前對象的屬性值 -
獲取這個 Bean 的注入模式,默認為 AUTOWIRE_NO,例如可以通過
@Bean注解的autowire屬性配置注入模式- 如果注入模式為 AUTOWIRE_BY_NAME 或者 AUTOWIRE_BY_TYPE,則通過下面的方式獲取屬性值
- 將
pvs封裝成 MutablePropertyValues 對象newPvs(允許對屬性進行相關操作) - AUTOWIRE_BY_NAME 模式,通過名稱獲取相關屬性值,保存在
newPvs中,調用autowireByName(...)方法 - AUTOWIRE_BY_TYPE 模式,通過類型獲取相關屬性值,保存在
newPvs中,調用autowireByType(...)方法 - 將
newPvs復制給pvs
-
通過 InstantiationAwareBeanPostProcessor 處理器(如果有)對
pvs進行處理- 遍歷所有的 BeanPostProcessor
- 如果為 InstantiationAwareBeanPostProcessor 類型,則調用其
postProcessProperties(...)方法,對pvs進行后置處理 - 如果上一步的處理結果為空,可能是新版本導致的(Spring 5.1 之前沒有上面這個方法),則需要兼容老版本
- 嘗試找到這個 Bean 的所有
java.beans.PropertyDescriptor屬性描述器(包含這個屬性的所有信息) - 調用處理器的
postProcessPropertyValues(...)方法,對pvs進行后置處理 - 如果處理后的 PropertyValues 對象為空,直接
return,則不會調用后面的處理器,也不會進行接下來的屬性填充
- 嘗試找到這個 Bean 的所有
- 將處理后的
pvsToUse復制給pvs
-
依賴檢查
- 找到這個 Bean 的所有
java.beans.PropertyDescriptor屬性描述器(包含這個屬性的所有信息) - 進行依賴檢查,如果沒有找到對應的屬性值,則根據檢查策略進行拋出異常(默認不會)
- 找到這個 Bean 的所有
-
如果
pvs不為空,則將里面的屬性值設置到當前 Bean 對應的屬性中(依賴注入),調用applyPropertyValues(...)方法前面找到的屬性值並沒有設置到 Bean 中,且屬性值可能是一個表達式,類型也可能也不對,需要先進行處理和類型轉換,然后再設置到該實例對象中
整個的屬性填充過程非常的復雜,接下來進行概括:
- 允許你對實例化對象進行后置處理,處理結果為
false表示不需要進行接下來的屬性填充過程 - 根據注入模式,找到沒有配置屬性值的對象屬性,然后找到對應的 Bean,默認注入模式為不注入
- 允許你對屬性值進行后置處理,例如
@Autowired、@Value等注解標注的屬性會通過這里找到對應的屬性值(或對象) - 上述過程僅找到了屬性值,還沒設置到當前實例對象中,所以最后一步才是真正的屬性填充
上面有兩種注入模式:AUTOWIRE_BY_NAME 和 AUTOWIRE_BY_TYPE,默認為 AUTOWIRE_NO,接下來先來看看這兩種注入模式的實現
通過名稱獲取屬性值
autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) 方法,通過名稱獲取相關屬性值,如下:
// AbstractAutowireCapableBeanFactory.java
protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// <1> 獲取當前 Bean 中不滿意的非簡單類型的屬性名稱,也就是沒有定義屬性值的"對象"屬性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
// <2> 遍歷這些對象屬性的名稱
for (String propertyName : propertyNames) {
// <3> 如果當前容器存在對應的 Bean(通過名稱判斷)
if (containsBean(propertyName)) {
// <3.1> 根據屬性名稱獲取對應的 `bean` 對象(依賴查找)
Object bean = getBean(propertyName);
// <3.2> 將 `bean` 添加至 `pvs`
pvs.add(propertyName, bean);
// <3.3> 將兩個 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 中不滿意的非簡單類型的屬性名稱,也就是沒有定義屬性值的"對象"屬性,如下:
// AbstractAutowireCapableBeanFactory.java protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) { Set<String> result = new TreeSet<>(); // 獲取已設置的屬性值 PropertyValues pvs = mbd.getPropertyValues(); // 找到這個 Bean 的所有 PropertyDescriptor 屬性描述器(包含這個屬性的所有信息) PropertyDescriptor[] pds = bw.getPropertyDescriptors(); // 遍歷所有屬性 for (PropertyDescriptor pd : pds) { if (pd.getWriteMethod() != null // 有可寫方法 && !isExcludedFromDependencyCheck(pd) // 不忽略 && !pvs.contains(pd.getName()) // 沒有對應的屬性值 && !BeanUtils.isSimpleProperty(pd.getPropertyType())) // 不是簡單類型(例如一個實體類) { result.add(pd.getName()); } } // 返回這些不滿意的非簡單類型的屬性 return StringUtils.toStringArray(result); } -
遍歷這些對象屬性的名稱
-
如果當前容器存在對應的 Bean(通過名稱判斷)
- 根據屬性名稱獲取對應的
bean對象(依賴查找) - 將
bean添加至pvs - 將兩個 Bean 之間的依賴關系保存起來
- 根據屬性名稱獲取對應的
直接根據"對象"名稱通過 getBean(String beanName) 獲取到對應的對象(依賴查找)
通過類型獲取屬性值
autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) 方法,通過類型獲取相關屬性值,如下:
// AbstractAutowireCapableBeanFactory.java
protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// <1> 獲取 TypeConverter 類型轉換器,用於取代默認的 PropertyEditor 類型轉換器
// 例如 Spring 3.0 之后的 ConversionService
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
// <2> 獲取當前 Bean 中不滿意的非簡單類型的屬性名稱,也就是沒有定義屬性值的"對象"屬性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
// <3> 遍歷這些對象屬性的名稱
for (String propertyName : propertyNames) {
try {
// <3> 獲取這個屬性的 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有信息)
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// <4> 如果不是 Object 類型(對 Object 類類型的 Bean 進行自動裝配毫無意義),則嘗試找到對應的對象
if (Object.class != pd.getPropertyType()) {
// <5> 找到這個屬性的寫方法
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);
// <6> 創建對應的依賴注入描述對象
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// <7> 依賴注入,找到該屬性對應的對象
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
// <8> 如果找到屬性對象,則將該其添加至 `pvs`
if (autowiredArgument != null) {
pvs.add(propertyName, autowiredArgument);
}
// <9> 將注入的屬性對象和當前 Bean 之前的關系保存起來
// 因為該屬性可能是一個集合,找到了多個對象,所以這里是一個數組
for (String autowiredBeanName : autowiredBeanNames) {
// 將 `autowiredBeanName` 與 `beanName` 的依賴關系保存
registerDependentBean(autowiredBeanName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
// 清空 `autowiredBeanName` 數組
autowiredBeanNames.clear();
}
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
過程大致如下:
- 獲取 TypeConverter 類型轉換器,用於取代默認的 PropertyEditor 類型轉換器
- 獲取當前 Bean 中不滿意的非簡單類型的屬性名稱,也就是沒有定義屬性值的"對象"屬性,和通過名稱注入的過程一樣
- 遍歷這些"對象"屬性的名稱,獲取這個屬性的
java.beans.PropertyDescriptor屬性描述器(包含這個屬性的所有信息) - 如果不是 Object 類型(對 Object 類類型的 Bean 進行自動裝配毫無意義),則嘗試找到對應的對象
- 找到這個屬性的寫方法
- 創建對應的 DependencyDescriptor 依賴注入描述對象,默認 required 為 false,表示找不到也沒關系
- 依賴注入,找到該屬性對應的對象,調用
resolveDependency(...)方法 - 如果找到屬性對象,則將該其添加至
pvs - 將注入的屬性對象和當前 Bean 之前的關系保存起來
根據"對象"名稱通過 resolveDependency(...) 獲取到對應的對象,該方法就是依賴注入的底層實現,整個過程也非常復雜,所以將這部分內容放在下一篇《@Autowired 等注解的實現原理》文章中
屬性值的后置處理
調用 InstantiationAwareBeanPostProcessor#postProcessProperties 方法,對前面屬性值進行處理
在前面的AUTOWIRE_BY_NAME 和 AUTOWIRE_BY_TYPE兩種注入模式中,找到的都是普通對象的屬性值,例如 @Autowired、@Value 和 @Resource 注解並沒有被解析,且默認的注入模式還是AUTOWIRE_NO,那這些注解是如何被解析的呢?Spring 內部有下面兩個 InstantiationAwareBeanPostProcessor 處理器:
- AutowiredAnnotationBeanPostProcessor,解析 @Autowired 和 @Value 注解標注的屬性,獲取對應屬性值
- CommonAnnotationBeanPostProcessor,會解析 @Resource 注解標注的屬性,獲取對應的屬性值
這里先提一下,具體的實現過程在下一篇《@Autowired 等注解的實現原理》文章中進行分析
屬性填充
applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) 方法,屬性填充
如果獲取到的 pvs 屬性值對象不為空,則將里面的屬性值設置到當前 Bean 對應的屬性中(依賴注入),我們知道前面找到的屬性值並沒有設置到 Bean 中,且屬性值可能是一個表達式,類型也可能也不對,需要先進行處理和類型轉換,然后再設置到該實例對象中,方法如下:
// AbstractAutowireCapableBeanFactory.java
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
// <1> 沒有相關屬性值,則直接 `return` 返回
if (pvs.isEmpty()) {
return;
}
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
// ------------------------開始屬性值的轉換與填充------------------------
MutablePropertyValues mpvs = null;
// 定義一個 `original` 集合,承載屬性值(未進行轉換)
List<PropertyValue> original;
// <2> 如果 `pvs` 是 MutablePropertyValues 類型,則可能已經處理過了
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
// <2.1> 屬性值已經轉換了,則將這些屬性值設置到當前 Bean 中(反射機制),依賴注入的最終實現!!!
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
// <2.2> 沒有轉換過,則獲取所有的屬性值集合
original = mpvs.getPropertyValueList();
}
else {
// <2.2> 獲取所有的屬性值集合
original = Arrays.asList(pvs.getPropertyValues());
}
// 獲取 TypeConverter 類型轉換器,用於取代默認的 PropertyEditor 類型轉換器
// 例如 Spring 3.0 之后的 ConversionService
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.
// <3> 定義一個 `deepCopy` 集合,保存轉換后的屬性值
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
// <4> 遍歷所有的屬性值,進行轉換(如果有必要)
for (PropertyValue pv : original) {
// <4.1> 已經轉換過,則直接添加到 `deepCopy` 中
if (pv.isConverted()) {
deepCopy.add(pv);
}
// <4.2> 否則,開始進行轉換
else {
String propertyName = pv.getName();
// 轉換之前的屬性值
Object originalValue = pv.getValue();
// <4.2.1> 表達式的處理(如果有必要的話),例如你在 XML 配置的屬性值為 `${systenm.user}`,則會解析出對應的值
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
// 轉換之后的屬性值
Object convertedValue = resolvedValue;
// 該屬性是否可以轉換
boolean convertible = bw.isWritableProperty(propertyName) && // 屬性可寫
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); // 不包含 `.` 和 `[`
if (convertible) {
// <4.2.2> 使用類型轉換器轉換屬性值(如果有必要的話)
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) {
// <4.2.3> 設置轉換后的值,避免上面的各種判斷
pv.setConvertedValue(convertedValue);
}
// <4.2.4> 添加到 `deepCopy` 中
deepCopy.add(pv);
}
// 屬否則屬性值進行了轉換
else if (convertible // 可轉換的
&& originalValue instanceof TypedStringValue // 屬性原始值是字符串類型
&& !((TypedStringValue) originalValue).isDynamic() // 屬性的原始類型值不是動態生成的字符串
&& !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) // 屬性的原始值不是集合或者數組類型
{
// <4.2.3> 設置轉換后的值,避免上面的各種判斷
pv.setConvertedValue(convertedValue);
// <4.2.4> 添加到 `deepCopy` 中
deepCopy.add(pv);
}
// 否則
else {
// 這個屬性每次都要處理,不能緩存
resolveNecessary = true;
// <4.2.4> 添加到 `deepCopy` 中
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
// <5> 如果屬性值不為空,且不需要每次都處理,則設置為已轉換
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
// <6> 將屬性值設置到當前 Bean 中(反射機制),依賴注入的最終實現!!!
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
過程大致如下:
- 沒有相關屬性值,則直接
return返回
開始屬性值的轉換與填充,先定義一個 original 集合,承載屬性值(未進行轉換)
-
如果
pvs是 MutablePropertyValues 類型,則可能已經處理過了,否則,獲取所有的屬性值集合,放入original集合中-
屬性值已經轉換了,則將這些屬性值設置到當前 Bean 中(反射機制),依賴注入的最終實現!!!
調用
BeanWrapperImpl#setPropertyValues(PropertyValues)方法 -
沒有轉換過,則獲取所有的屬性值集合,放入
original集合中
-
-
定義一個
deepCopy集合,保存轉換后的屬性值 -
遍歷所有的屬性值,進行轉換(如果有必要)
- 已經轉換過,則直接添加到
deepCopy中 - 否則,開始進行轉換
- 表達式的處理(如果有必要的話),例如你在 XML 配置的屬性值為
${systenm.user},則會解析出對應的值 - 使用類型轉換器轉換屬性值(如果有必要的話)
- 設置轉換后的值,避免上面的各種判斷
- 添加到
deepCopy中
- 表達式的處理(如果有必要的話),例如你在 XML 配置的屬性值為
- 已經轉換過,則直接添加到
-
如果屬性值不為空,且不需要每次都處理,則設置為已轉換
-
將屬性值設置到當前 Bean 中(反射機制),依賴注入的最終實現!!!
調用
BeanWrapperImpl#setPropertyValues(PropertyValues)方法
整個屬性注入過程非常復雜,上面僅列出了關鍵步驟,可以看到最終會調用 BeanWrapperImpl#setPropertyValues(PropertyValues) 方法將屬性值設置到 Bean 中
在 Bean 的實例化階段獲取到的就是一個 BeanWrapperImpl 對象,所以這里調用的就是當前 Bean 的 setPropertyValues(PropertyValues) 方法,該方法的底層借助於 Java Beans 的 java.beans.PropertyDescriptor 屬性描述器,獲取到對應的寫方法,然后通過反射機制設置當前 Bean 的屬性值
總結
當我們顯示或者隱式地調用AbstractBeanFactory 的 getBean(...) 方法時,會觸發 Bean 的加載,在《開啟 Bean 的加載》文章中分析了整個加載過程。
對於不同作用域的 Bean,底層都會調用 AbstractAutowireCapableBeanFactory 的 createBean(...) 方法進行創建,在《Bean 的創建過程》文章中分析了整個創建過程。創建 Bean 的過程中,在獲取到的一個實例對象后,需要獲取相關屬性值,然后注入到 Bean 中,其中獲取屬性值有三種模式:
-
AUTOWIRE_NO,默認,不獲取相關屬性值
-
AUTOWIRE_BY_NAME,通過名稱獲取沒有定義屬性值的"對象"的屬性值,通過
getBean(String beanName)查找 -
AUTOWIRE_BY_TYPE,通過類型獲取沒有定義屬性值的"對象"的屬性值,依賴注入的方式
默認情況下,獲取到已定義的屬性值后不會通過上面的方式去找屬性值,在后續有一個屬性值的后置處理,會調用所有的 InstantiationAwareBeanPostProcessor 處理器的 postProcessProperties 方法進行處理,例如 Spring 內部有兩個 InstantiationAwareBeanPostProcessor 處理器:
- AutowiredAnnotationBeanPostProcessor,解析 @Autowired 和 @Value 注解標注的屬性,獲取對應屬性值
- CommonAnnotationBeanPostProcessor,會解析 @Resource 注解標注的屬性,獲取對應的屬性值
在獲取到所有的屬性值后然后通過反射機制設置到 Bean 中
關於 @Autowired、@Value 和 @Resource 注解的實現原理將在下一篇《@Autowired 等注解的實現原理》文章中進行分析
