1. 程式人生 > >死磕Spring之IoC篇 - Bean 的屬性填充階段

死磕Spring之IoC篇 - Bean 的屬性填充階段

> 該系列文章是本人在學習 Spring 的過程中總結下來的,裡面涉及到相關原始碼,可能對讀者不太友好,請結合我的原始碼註釋 [Spring 原始碼分析 GitHub 地址](https://github.com/liu844869663/spring-framework) 進行閱讀 > > Spring 版本:5.1.14.RELEASE > > 開始閱讀這一系列文章之前,建議先檢視[**《深入瞭解 Spring IoC(面試題)》**](https://www.cnblogs.com/lifullmoon/p/14422101.html)這一篇文章 > > 該系列其他文章請檢視:[**《死磕 Spring 之 IoC 篇 - 文章導讀》**](https://www.cnblogs.com/lifullmoon/p/14436372.html) ## Bean 的屬性填充階段 當我們顯示或者隱式地呼叫`AbstractBeanFactory` 的 `getBean(...)` 方法時,會觸發 Bean 的載入,在[**《開啟 Bean 的載入》**](https://www.cnblogs.com/lifullmoon/p/14452795.html)文章中分析了整個載入過程。 對於不同作用域的 Bean,底層都會呼叫 `AbstractAutowireCapableBeanFactory` 的 `createBean(...) `方法進行建立,在[**《Bean 的建立過程》**](https://www.cnblogs.com/lifullmoon/p/14452842.html)文章中分析了整個建立過程。建立 Bean 的過程中,在獲取到的一個例項物件後,裡面的相關屬性也許是空的,那麼接下來要做的就是將需要填充的屬性進行依賴注入,然後再進行後續的初始化工作。整個的屬性填充過程非常複雜,因為配置的屬性值可能是一個表示式,需要解析,型別也可能不對,需要進行型別轉換,還可能是一個物件,需要找到對應的 Bean 然後注入(**依賴注入**),存在有各種處理,本文將會分析建立 Bean 過程中的屬性填充階段。 ### 回顧 先來回顧一下建立 Bean 過程中屬性填充階段對應的程式碼: ```java // 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)` 方法,屬性填充,如下: ```java // 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); } } ``` 過程大致如下: 1. 如果例項物件為`null`,則進行下面的判斷 1. 這個 Bean 有屬性,則丟擲異常 2. 否則,不用屬性填充,直接 `return` 2. **例項化**階段的**後置處理**,如果滿足這兩個條件:RootBeanDefinition 不是使用者定義的(由 Spring 解析出來的)、是否有 InstantiationAwareBeanPostProcessor 處理器 1. 遍歷所有的 BeanPostProcessor 2. 如果為 InstantiationAwareBeanPostProcessor 型別,則對例項化物件進行後置處理 注意,如果返回 false,直接 `return`,不會呼叫後面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充 3. 獲取 `pvs`,承載當前物件的屬性值 4. 獲取這個 Bean 的注入模式,預設為 **AUTOWIRE_NO**,例如可以通過 `@Bean` 註解的 `autowire` 屬性配置注入模式 1. 如果注入模式為 **AUTOWIRE_BY_NAME** 或者 **AUTOWIRE_BY_TYPE**,則通過下面的方式獲取屬性值 2. 將 `pvs` 封裝成 MutablePropertyValues 物件 `newPvs`(允許對屬性進行相關操作) 3. **AUTOWIRE_BY_NAME** 模式,通過名稱獲取相關屬性值,儲存在 `newPvs` 中,呼叫 `autowireByName(...)` 方法 4. **AUTOWIRE_BY_TYPE** 模式,通過型別獲取相關屬性值,儲存在 `newPvs` 中,呼叫 `autowireByType(...)` 方法 5. 將 `newPvs` 複製給 `pvs` 5. 通過 InstantiationAwareBeanPostProcessor 處理器(如果有)對 `pvs` 進行處理 1. 遍歷所有的 BeanPostProcessor 2. 如果為 InstantiationAwareBeanPostProcessor 型別,則呼叫其 `postProcessProperties(...)` 方法,對 `pvs` 進行後置處理 3. 如果上一步的處理結果為空,可能是新版本導致的(Spring 5.1 之前沒有上面這個方法),則需要**相容老版本** 1. 嘗試找到這個 Bean 的所有 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有資訊) 2. 呼叫處理器的 `postProcessPropertyValues(...)` 方法,對 `pvs` 進行後置處理 3. 如果處理後的 PropertyValues 物件為空,直接 `return`,則不會呼叫後面的處理器,也不會進行接下來的屬性填充 4. 將處理後的 `pvsToUse` 複製給 `pvs` 6. 依賴檢查 1. 找到這個 Bean 的所有 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有資訊) 2. 進行依賴檢查,如果沒有找到對應的屬性值,則根據檢查策略進行丟擲異常(預設不會) 7. 如果 `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)` 方法,通過名稱獲取相關屬性值,如下: ```java // 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"); } } } } ``` 過程並不複雜,大致如下: 1. 獲取當前 Bean 中不滿意的非簡單型別的屬性名稱,也就是沒有定義屬性值的**"物件"**屬性,如下: ```java // AbstractAutowireCapableBeanFactory.java protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) { Set 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); } ``` 2. 遍歷這些物件屬性的名稱 3. 如果當前容器存在對應的 Bean(通過名稱判斷) 1. 根據屬性名稱獲取對應的 `bean` 物件(**依賴查詢**) 2. 將 `bean` 新增至 `pvs` 3. 將兩個 Bean 之間的依賴關係儲存起來 直接根據**"物件"**名稱通過 `getBean(String beanName)` 獲取到對應的物件(**依賴查詢**) ### 通過型別獲取屬性值 `autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs)` 方法,通過型別獲取相關屬性值,如下: ```java // 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 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); } } } ``` 過程大致如下: 1. 獲取 TypeConverter 型別轉換器,用於取代預設的 PropertyEditor 型別轉換器 2. 獲取當前 Bean 中不滿意的非簡單型別的屬性名稱,也就是沒有定義屬性值的**"物件"**屬性,和**通過名稱注入**的過程一樣 3. 遍歷這些**"物件"**屬性的名稱,獲取這個屬性的 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有資訊) 4. 如果不是 Object 型別(對 Object 類型別的 Bean 進行自動裝配毫無意義),則嘗試找到對應的物件 5. 找到這個屬性的寫方法 6. 建立對應的 DependencyDescriptor 依賴注入描述物件,預設 required 為 false,表示找不到也沒關係 7. 依賴注入,找到該屬性對應的物件,呼叫 `resolveDependency(...)` 方法 8. 如果找到屬性物件,則將該其新增至 `pvs` 9. 將注入的屬性物件和當前 Bean 之前的關係儲存起來 根據**"物件"**名稱通過 `resolveDependency(...)` 獲取到對應的物件,該方法就是**依賴注入**的底層實現,整個過程也非常複雜,所以將這部分內容放在下一篇[**《@Autowired 等註解的實現原理》**](https://www.cnblogs.com/lifullmoon/p/14453011.html)文章中 ### 屬性值的後置處理 呼叫 `InstantiationAwareBeanPostProcessor#postProcessProperties` 方法,對前面屬性值進行處理 在前面的**AUTOWIRE_BY_NAME** 和 **AUTOWIRE_BY_TYPE**兩種注入模式中,找到的都是普通物件的屬性值,例如 @Autowired、@Value 和 @Resource 註解並沒有被解析,且預設的注入模式還是**AUTOWIRE_NO**,那這些註解是如何被解析的呢?Spring 內部有下面兩個 InstantiationAwareBeanPostProcessor 處理器: - AutowiredAnnotationBeanPostProcessor,解析 @Autowired 和 @Value 註解標註的屬性,獲取對應屬性值 - CommonAnnotationBeanPostProcessor,會解析 @Resource 註解標註的屬性,獲取對應的屬性值 這裡先提一下,具體的實現過程在下一篇[**《@Autowired 等註解的實現原理》**](https://www.cnblogs.com/lifullmoon/p/14453011.html)文章中進行分析 ### 屬性填充 `applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)` 方法,屬性填充 如果獲取到的 `pvs` 屬性值物件不為空,則將裡面的屬性值設定到當前 Bean 對應的屬性中(依賴注入),我們知道前面找到的屬性值並沒有設定到 Bean 中,且屬性值可能是一個表示式,型別也可能也不對,需要先進行處理和型別轉換,然後再設定到該例項物件中,方法如下: ```java // 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 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 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); } } ``` 過程大致如下: 1. 沒有相關屬性值,則直接 `return` 返回 ------ 開始屬性值的轉換與填充,先定義一個 `original` 集合,承載屬性值(未進行轉換) 2. 如果 `pvs` 是 MutablePropertyValues 型別,則可能已經處理過了,否則,獲取所有的屬性值集合,放入 `original` 集合中 1. 屬性值已經轉換了,則將這些屬性值設定到當前 Bean 中(反射機制),**依賴注入**的最終實現!!! 呼叫 `BeanWrapperImpl#setPropertyValues(PropertyValues)` 方法 2. 沒有轉換過,則獲取所有的屬性值集合,放入 `original` 集合中 3. 定義一個 `deepCopy` 集合,儲存轉換後的屬性值 4. 遍歷所有的屬性值,進行轉換(如果有必要) 1. 已經轉換過,則直接新增到 `deepCopy` 中 2. 否則,開始進行轉換 1. 表示式的處理(如果有必要的話),例如你在 XML 配置的屬性值為 `${systenm.user}`,則會解析出對應的值 2. 使用型別轉換器轉換屬性值(如果有必要的話) 3. 設定轉換後的值,避免上面的各種判斷 4. 新增到 `deepCopy` 中 5. 如果屬性值不為空,且不需要每次都處理,則設定為已轉換 6. 將屬性值設定到當前 Bean 中(反射機制),**依賴注入**的最終實現!!! 呼叫 `BeanWrapperImpl#setPropertyValues(PropertyValues)` 方法 ------ 整個屬性注入過程非常複雜,上面僅列出了關鍵步驟,可以看到最終會呼叫 `BeanWrapperImpl#setPropertyValues(PropertyValues)` 方法將屬性值設定到 Bean 中 在 Bean 的例項化階段獲取到的就是一個 BeanWrapperImpl 物件,所以這裡呼叫的就是當前 Bean 的 `setPropertyValues(PropertyValues)` 方法,該方法的底層藉助於 Java Beans 的 `java.beans.PropertyDescriptor` 屬性描述器,獲取到對應的寫方法,然後通過反射機制設定當前 Bean 的屬性值 ### 總結 當我們顯示或者隱式地呼叫`AbstractBeanFactory` 的 `getBean(...)` 方法時,會觸發 Bean 的載入,在[**《開啟 Bean 的載入》**](https://www.cnblogs.com/lifullmoon/p/14452795.html)文章中分析了整個載入過程。 對於不同作用域的 Bean,底層都會呼叫 `AbstractAutowireCapableBeanFactory` 的 `createBean(...) `方法進行建立,在[**《Bean 的建立過程》**](https://www.cnblogs.com/lifullmoon/p/14452842.html)文章中分析了整個建立過程。建立 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 等註解的實現原理》**](https://www.cnblogs.com/lifullmoon/p/14453011.html)文章中進