該系列文章是本人在學習 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 等註解的實現原理》文章中進行分析