所有文章已遷移至csdn腹侣,csdn個(gè)人主頁(yè)https://blog.csdn.net/chaitoudaren
spring屬性注入分4種:
- 不開(kāi)啟自動(dòng)注入,即xml自己配置property
- 通過(guò)名稱自動(dòng)注入
- 通過(guò)類型自動(dòng)注入
- @Autowire自動(dòng)注入
本篇我們將介紹前三種磕道,@Autowire應(yīng)該是百分之99的開(kāi)發(fā)者選擇的的注入方式,它通過(guò)屬性填充中的后置處理器完成,因此本篇有涉及后置處理器的不用太糾結(jié)枪孩,將單獨(dú)一片詳解:spring源碼日期16: @Autowired實(shí)現(xiàn)原理
下方代碼,本篇只關(guān)心第4點(diǎn)屬性填充
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
...
try {
//
/**
* 4. 填充屬性
* 如果@Autowired注解屬性藻肄,則在上方完成解析后蔑舞,在這里完成注入
*
* @Autowired
* private Inner inner;
*/
populateBean(beanName, mbd, instanceWrapper);
// 5. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
...
}
屬性填充
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 如果BeanWrapper對(duì)象為null
if (bw == null) {
if (mbd.hasPropertyValues()) {
// 有屬性但是沒(méi)對(duì)象,那往哪里注入...直接拋異常了
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
// 沒(méi)有屬性就直接返回
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.
// 1. 實(shí)例化后的后置操作
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
// 實(shí)例化后置處理器可以發(fā)出終止填充的命令嘹屯,這點(diǎn)比較特別
return;
}
}
}
}
// 2. 獲取屬性值
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 3. 根據(jù)注入方式的不同可分為 通過(guò) ①名稱注入攻询、②類型注入、③不自動(dòng)注入
/**
* ①按名稱注入州弟,則pvs在步驟2時(shí)會(huì)獲取到配置文件中配置注入的屬性钧栖,同時(shí)在autowireByName又會(huì)進(jìn)一步通過(guò)名稱添加補(bǔ)充
* ②按名稱注入,則pvs在步驟2時(shí)會(huì)獲取到配置文件中配置注入的屬性婆翔,同時(shí)在autowireByType又會(huì)進(jìn)一步通過(guò)類型添加補(bǔ)充
* ③不開(kāi)啟自動(dòng)注入拯杠,則在步驟2 pvs就可以獲取到配置文件中注入的屬性
*/
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) {
// ①通過(guò)名稱自動(dòng)注入
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// ②通過(guò)類型自動(dòng)注入
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 判斷所有實(shí)例化后置處理器是否都已經(jīng)初始化完成
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 依賴檢測(cè)
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
/**
* 4. 屬性填充的后置處理器
* @Autowired
* private Inner inner;
* 在這里使用AutowiredAnnotationBeanPostProcessor進(jìn)行注入
*/
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// @Autowired正是在這里調(diào)用后置處理器對(duì)屬性進(jìn)行注入
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 對(duì)所有需要檢測(cè)的屬性進(jìn)行后置處理
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
// 5. 將屬性應(yīng)用到bean中
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
- 實(shí)例化后置處理
- 獲取屬性值
這邊獲取到的pvs是從配置文件中獲取的,代碼如下啃奴,xml配置文件中property標(biāo)簽僅包含b1潭陪,所以pvs僅僅會(huì)獲取到b1,如果沒(méi)有下一步的代碼將不會(huì)注入b2(這點(diǎn)很容易被忽視,一定引起重視)
public Class A {
private B1 b1;
private B2 b2;
// getter&&setter
}
public Class B1 {}
public Class B2 {}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"
default-autowire="byName"
>
<bean id="a" class="autowire.A">
<property name="b1" ref="b1"/>
</bean>
<bean id="b1" class="B1"/>
<bean id="b2" class="B2"/>
</beans>
- 自動(dòng)注入(其實(shí)這里只是獲取待注入屬性依溯,并未開(kāi)始實(shí)際的注入操作)
還是上方代碼老厌,注意一定要加上default-autowire="byName"這句,這句指開(kāi)啟按名稱注入黎炉,否則spring默認(rèn)不開(kāi)啟自動(dòng)注入枝秤。開(kāi)啟后,spring將通過(guò)Class A類中的屬性拜隧,按名稱b2通過(guò)getBean("b2")的方式進(jìn)行查找宿百,并將它添加到pvs中,至此屬性b1, b2才都被成功添加到pvs中洪添,等待注入
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 獲取pvs以外的其他屬性垦页,該屬性必須有setter方法
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
// 直接通過(guò)屬性名獲取bean,并假如到pvs中
Object bean = getBean(propertyName);
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");
}
}
}
}
- 屬性填充的后置處理器干奢,@Autowire正是在這里注入的痊焊,我們將單獨(dú)一章詳解:spring源碼日期16: @Autowired實(shí)現(xiàn)原理
- 將屬性注入到bean中
代碼很大一部分工作用在了屬性轉(zhuǎn)換上,例如property傳入String類型而實(shí)際屬性則為int類型忿峻,當(dāng)然這是最簡(jiǎn)單的一種薄啥。而我們最關(guān)心的注入操作則發(fā)生在第6步,具體代碼很長(zhǎng)就不詳細(xì)分析了逛尚,但是最核心的操作則是通過(guò)反射獲取到對(duì)應(yīng)屬性field垄惧,然后調(diào)用field.set(bean, property);實(shí)現(xiàn)對(duì)bean屬性的賦值
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
// 1. pvs為空就沒(méi)得注入了
if (pvs.isEmpty()) {
return;
}
// 2. 權(quán)限管理器
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
//MutablePropertyValues是PropertyValues接口的默認(rèn)實(shí)現(xiàn)類
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
// 3. 獲取bean的屬性集合
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
// pvs都需要被轉(zhuǎn)換成對(duì)應(yīng)的類型才可以應(yīng)用到beanwapper中
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
// 如果pvs已經(jīng)轉(zhuǎn)換過(guò),則直接設(shè)置屬性值無(wú)需再次轉(zhuǎn)換
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
// 否則獲取原始PropertyValue集合
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
// 4. 獲取類型轉(zhuǎn)換器
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.
// 5. 通過(guò)深度拷貝,解析值引用
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
// 循環(huán)轉(zhuǎn)換PropertyValues
for (PropertyValue pv : original) {
// 已經(jīng)轉(zhuǎn)換過(guò),則直接加入deepCopy
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);
}
// 解析原始屬性值
// 當(dāng)注入集合屬性時(shí),如果指定了value-type,如value-type="java.lang.String",那么resolveValueIfNecessary會(huì)執(zhí)行類型的轉(zhuǎn)換操作
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
// isWritableProperty判斷屬性是否可寫(xiě)绰寞,isNestedOrIndexedProperty判斷是否索引屬性或者嵌套屬性
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
// 是否轉(zhuǎn)換
if (convertible) {
// 類型轉(zhuǎn)換
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.
// 緩存已經(jīng)轉(zhuǎn)換過(guò)的值,避免再次轉(zhuǎn)換到逊。這取決于convertForProperty是否真正對(duì)屬性進(jìn)行了轉(zhuǎn)換
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 {
// 6. 設(shè)置屬性值,實(shí)質(zhì)就是通過(guò)反射調(diào)用對(duì)屬性進(jìn)行賦值
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}