1. 程式人生 > 實用技巧 >Spring IoC 屬性賦值階段

Spring IoC 屬性賦值階段

前言

本系列全部基於 Spring 5.2.2.BUILD-SNAPSHOT 版本。因為 Spring 整個體系太過於龐大,所以只會進行關鍵部分的原始碼解析。

本篇文章主要介紹 Spring IoC 容器中 bean 的屬性賦值階段。

正文

我們在Spring IoC bean 的建立一文中分析建立 bean 例項的主要流程,此時創建出來的 bean 還是個屬性未賦值的例項,在建立完之後會進入 populateBean() 方法,即進入屬性賦值階段。我們簡單回顧一下,上次分析過的 doCreateBean() 方法:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {

    // 例項化 bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 如果bean的作用域是singleton,則需要移除未完成的FactoryBean例項的快取
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 通過建構函式反射建立bean的例項,但是屬性並未賦值,見下文詳解
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 獲取bean的例項
final Object bean = instanceWrapper.getWrappedInstance();
// 獲取bean的型別
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
} synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// BeanDefinition 合併後的回撥,見下文詳解
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
// 省略異常處理...
mbd.postProcessed = true;
}
} // bean的作用域是單例 && 允許迴圈引用 && 當前bean正在建立中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
// 如果允許bean提前曝光
if (earlySingletonExposure) {
// 將beanName和ObjectFactory形成的key-value對放入singletonFactories快取中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
} Object exposedObject = bean;
try {
// 給 bean 的屬性賦值
populateBean(beanName, mbd, instanceWrapper);
// 初始化 bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 省略部分程式碼
}

屬性賦值

AbstractAutowireCapableBeanFactory#populateBean

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 {
return;
}
} // 給InstantiationAwareBeanPostProcessors最後一次機會在屬性設定前來改變bean
// 例如:可以用來支援屬性注入的型別
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
// 這裡會呼叫bean例項化後的生命週期回撥,返回false會跳過下面的屬性賦值階段
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
// 獲取PropertyValues
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 獲取依賴注入型別
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 如果依賴注入型別是 byName 或者 byType
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 賦值pvs到可修改的MutablePropertyValues
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 根據名稱自動注入,見下文詳解
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 根據型別自動注入,見下文詳解
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
} // 是否有註冊InstantiationAwareBeanPostProcessors的實現類
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// 遍歷並找到InstantiationAwareBeanPostProcessor的實現類,呼叫處理屬性值的後置處理方法
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);
// 如果屬性值的後置處理方法返回null,直接返回,不會進行底下的屬性值應用階段
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
} if (pvs != null) {
// 屬性填充,見下文詳解
applyPropertyValues(beanName, mbd, bw, pvs);
}
}

上面方法首先會呼叫 bean 的例項化後生命週期回撥方法,如果返回 false 會跳過下面的屬性賦值階段。關於 InstantiationAwareBeanPostProcessors 介面在Spring IoC bean 的建立一文中介紹過,這裡不再贅述。接著判斷是否是按 名稱 或者 型別 自動注入屬性並填入 newPvs 中,接著呼叫 bean 屬性填充前的生命週期回撥。屬性填充前生命週期回撥方法有兩個 postProcessProperties()postProcessPropertyValues(),第一個是 Spring 5.1 新加的,後面的是老的,已經被標記為過時;首先會呼叫 postProcessProperties() 如果返回空呼叫 postProcessPropertyValues(),否則直接使用返回的 PropertyValuespostProcessPropertyValues() 如果返回空會直接跳過屬性填充階段,不為空直接使用返回的 PropertyValues

按照名稱依賴注入

AbstractAutowireCapableBeanFactory#autowireByName

protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 尋找bw中需要依賴注入的屬性名稱
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
// 遍歷需要注入的bean
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
// 呼叫getBean()方法獲取bean
Object bean = getBean(propertyName);
// 將需要注入bean的例項加入到pvs
pvs.add(propertyName, bean);
// 註冊依賴關係
registerDependentBean(propertyName, beanName);
}
}
}

上面的方法很簡單,就是尋找 bean 的非簡單型別並且不存在於 mbd.getPropertyValues() 中的屬性,然後遍歷呼叫 getBean() 方法去獲取例項,完成注入。

非簡單型別就是指除去8個原始型別、String型別、Number型別、Date型別、URL型別、URI型別的其它型別。

registerDependentBean() 方法在Spring IoC bean 的載入一文中有分析過,這裡不再贅述。

按照型別依賴注入

AbstractAutowireCapableBeanFactory#autowireByType

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);
// 獲取bean中非簡單屬性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// 根據型別注入永遠不要注入Object型別,你細細地品一下
if (Object.class != pd.getPropertyType()) {
// 獲取屬性的可寫方法,一般是set方法
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 依賴解決,最後返回符合條件需要注入的bean例項
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
// 需要注入的bean例項不為空,加入到pvc
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
// 註冊依賴關係
registerDependentBean(autowiredBeanName, beanName);
}
autowiredBeanNames.clear();
}
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}

上面方法中的 resolveDependency() 方法在Spring IoC bean 的建立一文中介紹過,這裡不再贅述。

屬性賦值

AbstractAutowireCapableBeanFactory#applyPropertyValues

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;
// 快捷方式,如果屬性已經轉換過,直接填充進BeanWrapper
if (mpvs.isConverted()) {
try {
bw.setPropertyValues(mpvs);
return;
} catch (BeansException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
// 屬性沒有轉換過,獲取屬性列表
original = mpvs.getPropertyValueList();
} else {
// 獲取屬性列表
original = Arrays.asList(pvs.getPropertyValues());
} TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
// 獲取對應的解析器
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter); // 建立深拷貝,解決引用的問題
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
// 遍歷屬性,將屬性轉換為對應的型別
for (PropertyValue pv : original) {
// 如果pv型別轉換過,直接新增進deepCopy
if (pv.isConverted()) {
deepCopy.add(pv);
} else {
// 進行轉換
// 拿到pv原始屬性名和屬性值
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);
}
// 在合併的BeanDefinition中儲存轉換後的值,以避免為每個建立的bean例項重新轉換
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();
} try {
// 填充bean屬性值
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
} catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}

上面程式碼中的 bw.setPropertyValues() 方法最終會呼叫 BeanWrapperImpl#setVlaue() 方法,如下:

public void setValue(final @Nullable Object value) throws Exception {
// 這裡一般就是set方法
final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor)this.pd).getWriteMethodForActualAccess() : this.pd.getWriteMethod());
// 利用反射呼叫set方法給屬性賦值
ReflectionUtils.makeAccessible(writeMethod);
writeMethod.invoke(getWrappedInstance(), value); }

下圖是我 debug 時的截圖,可以看到基本上就是在呼叫屬性的 setter 方法:

注意:沒有 setter 方法時會丟擲異常。

總結

本篇文章主要分析了 Spring IoC 的屬性賦值階段的流程,Spring 在此階段也提供了2個擴充套件點;分別是 bean 的例項化後和屬性賦值前,即 InstantiationAwareBeanPostProcessor 介面的 postProcessAfterInstantiation() 方法和 postProcessProperties() 方法。需要注意的是在 XML 中配置的 autowire 屬性,不管是 byName 還是 byType 都需要 setter 方法,但是我們平時在使用 @Autowire 註解時並不需要 settter 方法,原因會在分析 @Autowire 註解時講述。