26--Spring建立Bean的過程(八),bean屬性填充應用屬性值
阿新 • • 發佈:2019-01-22
前兩個小節,已經分析了bean屬性的解析和轉換,轉換完之後,就可以應用屬性了,我們的例項中用的都是Setter方法注入,那麼自然會呼叫bean屬性的set方法對屬性進行注入。
開啟AbstractAutowireCapableBeanFactory類的applyPropertyValues方法,開始分析
// ⑦設定屬性值.
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
1. 迴圈獲取到的PropertyValue並設定屬性值
public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid) throws BeansException {
List<PropertyAccessException> propertyAccessExceptions = null;
// 獲取當前bean的所有屬性值
List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
((MutablePropertyValues) pvs).getPropertyValueList () : Arrays.asList(pvs.getPropertyValues()));
// 迴圈並設定屬性值
for (PropertyValue pv : propertyValues) {
try {
// This method may throw any BeansException, which won't be caught
// here, if there is a critical failure such as no matching field.
// We can attempt to deal only with less serious exceptions.
setPropertyValue(pv);
}
catch (NotWritablePropertyException ex) {
if (!ignoreUnknown) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
catch (NullValueInNestedPathException ex) {
if (!ignoreInvalid) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
catch (PropertyAccessException ex) {
if (propertyAccessExceptions == null) {
propertyAccessExceptions = new ArrayList<>();
}
propertyAccessExceptions.add(ex);
}
}
// If we encountered individual exceptions, throw the composite exception.
if (propertyAccessExceptions != null) {
PropertyAccessException[] paeArray = propertyAccessExceptions.toArray(new PropertyAccessException[0]);
throw new PropertyBatchUpdateException(paeArray);
}
}
至此我們已經得到了配置檔案中所有PropertyValue的集合,然後通過迴圈逐步將其值設定到bean中。
2.獲取PropertyTokenHolder物件並判斷應該設定key-value屬性還是本地屬性
public void setPropertyValue(PropertyValue pv) throws BeansException {
PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;
if (tokens == null) {
String propertyName = pv.getName();
AbstractNestablePropertyAccessor nestedPa;
try {
nestedPa = getPropertyAccessorForPropertyPath(propertyName);
}
catch (NotReadablePropertyException ex) {
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
"Nested property in path '" + propertyName + "' does not exist", ex);
}
tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
if (nestedPa == this) {
pv.getOriginalPropertyValue().resolvedTokens = tokens;
}
nestedPa.setPropertyValue(tokens, pv);
}
else {
setPropertyValue(tokens, pv);
}
}
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
// 設定配置檔案中的key:value對,例如.propertis中的屬性
if (tokens.keys != null) {
processKeyedProperty(tokens, pv);
}
// 設定本地屬性
else {
processLocalProperty(tokens, pv);
}
}
3.設定本地屬性
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
// PropertyHandler為null,或者方法不可寫的時候.
if (ph == null || !ph.isWritable()) {
//返回是否為可選值,即在目標類上不存在相應的屬性時將被忽略。
if (pv.isOptional()) {
return;
}
else {
throw createNotWritablePropertyException(tokens.canonicalName);
}
}
Object oldValue = null;
try {
Object originalValue = pv.getValue();
Object valueToApply = originalValue;
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
if (pv.isConverted()) {
valueToApply = pv.getConvertedValue();
}
else {
if (isExtractOldValueForEditor() && ph.isReadable()) {
try {
oldValue = ph.getValue();
}
// 省略異常列印資訊...
catch (Exception ex) {}
}
valueToApply = convertForProperty(tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
}
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
// 設定屬性
ph.setValue(valueToApply);
}
catch (TypeMismatchException ex) {
throw ex;
}
catch (InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
if (ex.getTargetException() instanceof ClassCastException) {
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
}
else {
Throwable cause = ex.getTargetException();
if (cause instanceof UndeclaredThrowableException) {
// May happen e.g. with Groovy-generated methods
cause = cause.getCause();
}
throw new MethodInvocationException(propertyChangeEvent, cause);
}
}
catch (Exception ex) {
PropertyChangeEvent pce = new PropertyChangeEvent(getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
throw new MethodInvocationException(pce, ex);
}
}
4.設定屬性
public void setValue(final @Nullable Object value) throws Exception {
// 獲取可寫方法,例如javaBean中的setXXX()方法
final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
this.pd.getWriteMethod());
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(writeMethod);
return null;
});
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
writeMethod.invoke(getWrappedInstance(), value), acc);
}
catch (PrivilegedActionException ex) {
throw ex.getException();
}
}
else {
ReflectionUtils.makeAccessible(writeMethod);
// 呼叫Method方法的invoke方法,通過反射方法為bean設定值
writeMethod.invoke(getWrappedInstance(), value);
}
}
5.總結
設定屬性的大體流程還是比較簡單的,首先獲取已經轉換的所有的配置檔案中bean的屬性;然後迴圈獲取到的屬性為javaBean設定值;獲取javaBean的可寫方法;通過Method的invoke方法,利用java的反射機制為javaBean設定值。