26--Spring创建Bean的过程(八),bean属性填充应用属性值

版权声明:如有转载,请标明出处,谢谢合作! https://blog.csdn.net/lyc_liyanchao/article/details/82821216

前两个小节,已经分析了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设置值。

猜你喜欢

转载自blog.csdn.net/lyc_liyanchao/article/details/82821216