Spring5源码分析(三) IOC容器的依赖注入— 基于XML的依赖注入(三)

七、BeanDefinitionValueResolver解析属性值

  当容器在对属性进行依赖注入时,如果发现属性值需要进行类型转换,如属性值是容器中另一个Bean实例对象的引用,则容器首先需要根据属性值解析出所引用的对象,然后才能将该引用对象注入到目标实例对象的属性上去,对属性进行解析的由 resolveValueIfNecessary 方法实现,其源码如下:

//解析属性值,对注入类型进行转换
@Nullable
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
    // We must check each value to see whether it requires a runtime reference
    // to another bean to be resolved.
    //对引用类型的属性进行解析
    if (value instanceof RuntimeBeanReference) {
        RuntimeBeanReference ref = (RuntimeBeanReference) value;
        //调用引用类型属性的解析方法
        return resolveReference(argName, ref);
    }
    //对属性值是引用容器中另一个Bean名称的解析
    else if (value instanceof RuntimeBeanNameReference) {
        String refName = ((RuntimeBeanNameReference) value).getBeanName();
        refName = String.valueOf(doEvaluate(refName));
        //从容器中获取指定名称的Bean
        if (!this.beanFactory.containsBean(refName)) {
            throw new BeanDefinitionStoreException(
                    "Invalid bean name '" + refName + "' in bean reference for " + argName);
        }
        return refName;
    }
    //对Bean类型属性的解析,主要是Bean中的内部类
    else if (value instanceof BeanDefinitionHolder) {
        // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
        BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
        return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
    }
    else if (value instanceof BeanDefinition) {
        // Resolve plain BeanDefinition, without contained name: use dummy name.
        BeanDefinition bd = (BeanDefinition) value;
        String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
                ObjectUtils.getIdentityHexString(bd);
        return resolveInnerBean(argName, innerBeanName, bd);
    }
    //对集合数组类型的属性解析
    else if (value instanceof ManagedArray) {
        // May need to resolve contained runtime references.
        ManagedArray array = (ManagedArray) value;
        //获取数组的类型
        Class<?> elementType = array.resolvedElementType;
        if (elementType == null) {
            //获取数组元素的类型
            String elementTypeName = array.getElementTypeName();
            if (StringUtils.hasText(elementTypeName)) {
                try {
                    //使用反射机制创建指定类型的对象
                    elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
                    array.resolvedElementType = elementType;
                }
                catch (Throwable ex) {
                    // Improve the message by showing the context.
                    throw new BeanCreationException(
                            this.beanDefinition.getResourceDescription(), this.beanName,
                            "Error resolving array type for " + argName, ex);
                }
            }
            //没有获取到数组的类型,也没有获取到数组元素的类型
            //则直接设置数组的类型为Object
            else {
                elementType = Object.class;
            }
        }
        //创建指定类型的数组
        return resolveManagedArray(argName, (List<?>) value, elementType);
    }
    //解析list类型的属性值
    else if (value instanceof ManagedList) {
        // May need to resolve contained runtime references.
        return resolveManagedList(argName, (List<?>) value);
    }
    //解析set类型的属性值
    else if (value instanceof ManagedSet) {
        // May need to resolve contained runtime references.
        return resolveManagedSet(argName, (Set<?>) value);
    }
    //解析map类型的属性值
    else if (value instanceof ManagedMap) {
        // May need to resolve contained runtime references.
        return resolveManagedMap(argName, (Map<?, ?>) value);
    }
    //解析props类型的属性值,props其实就是key和value均为字符串的map
    else if (value instanceof ManagedProperties) {
        Properties original = (Properties) value;
        //创建一个拷贝,用于作为解析后的返回值
        Properties copy = new Properties();
        original.forEach((propKey, propValue) -> {
            if (propKey instanceof TypedStringValue) {
                propKey = evaluate((TypedStringValue) propKey);
            }
            if (propValue instanceof TypedStringValue) {
                propValue = evaluate((TypedStringValue) propValue);
            }
            if (propKey == null || propValue == null) {
                throw new BeanCreationException(
                        this.beanDefinition.getResourceDescription(), this.beanName,
                        "Error converting Properties key/value pair for " + argName + ": resolved to null");
            }
            copy.put(propKey, propValue);
        });
        return copy;
    }
    //解析字符串类型的属性值
    else if (value instanceof TypedStringValue) {
        // Convert value to target type here.
        TypedStringValue typedStringValue = (TypedStringValue) value;
        Object valueObject = evaluate(typedStringValue);
        try {
            //获取属性的目标类型
            Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
            if (resolvedTargetType != null) {
                //对目标类型的属性进行解析,递归调用
                return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
            }
            //没有获取到属性的目标对象,则按Object类型返回
            else {
                return valueObject;
            }
        }
        catch (Throwable ex) {
            // Improve the message by showing the context.
            throw new BeanCreationException(
                    this.beanDefinition.getResourceDescription(), this.beanName,
                    "Error converting typed String value for " + argName, ex);
        }
    }
    else if (value instanceof NullBean) {
        return null;
    }
    else {
        return evaluate(value);
    }
}

//解析引用类型的属性值
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
    try {
        Object bean;
        //获取引用的Bean名称
        String refName = ref.getBeanName();
        refName = String.valueOf(doEvaluate(refName));
        //如果引用的对象在父类容器中,则从父类容器中获取指定的引用对象
        if (ref.isToParent()) {
            if (this.beanFactory.getParentBeanFactory() == null) {
                throw new BeanCreationException(
                        this.beanDefinition.getResourceDescription(), this.beanName,
                        "Can't resolve reference to bean '" + refName +
                        "' in parent factory: no parent factory available");
            }
            bean = this.beanFactory.getParentBeanFactory().getBean(refName);
        }
        //从当前的容器中获取指定的引用Bean对象,如果指定的Bean没有被实例化
        //则会递归触发引用Bean的初始化和依赖注入
        else {
            bean = this.beanFactory.getBean(refName);
            //将当前实例化对象的依赖引用对象
            this.beanFactory.registerDependentBean(refName, this.beanName);
        }
        if (bean instanceof NullBean) {
            bean = null;
        }
        return bean;
    }
    catch (BeansException ex) {
        throw new BeanCreationException(
                this.beanDefinition.getResourceDescription(), this.beanName,
                "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
    }
}

通过上面的代码分析,我们明白了Spring是如何将引用类型,内部类以及集合类型等属性进行解析的,属性值解析完成后就可以进行依赖注入了,依赖注入的过程就是Bean对象实例设置到它所依赖的Bean对象属性上去,在第 6 步中我们已经说过,依赖注入是通过 bw.setPropertyValues 方法实现的,该方法也使用了委托模式,在BeanWrapper接口中至少定义了方法声明,依赖注入的具体实现交由其实现类 BeanWrapperImpl 来完成,下面我们就分析依 BeanWrapperImpl 中赖注入相关的源码。

八、BeanWrapperImpl 对Bean属性的依赖注入

  BeanWrapperImpl类主要是对容器中完成初始化的Bean实例对象进行属性的依赖注入,即把Bean对象设置到它所依赖的另一个Bean的属性中去。然而,BeanWrapperImpl中的注入方法实际上由AbstractNestablePropertyAccessor 来实现的,其相关源码如下:

//实现属性依赖注入功能
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
    if (tokens.keys != null) {
        processKeyedProperty(tokens, pv);
    }
    else {
        processLocalProperty(tokens, pv);
    }
}

//实现属性依赖注入功能
@SuppressWarnings("unchecked")
private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) {
    //调用属性的getter(readerMethod)方法,获取属性的值
    Object propValue = getPropertyHoldingValue(tokens);
    PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
    if (ph == null) {
        throw new InvalidPropertyException(
                getRootClass(), this.nestedPath + tokens.actualName, "No property handler found");
    }
    Assert.state(tokens.keys != null, "No token keys");
    String lastKey = tokens.keys[tokens.keys.length - 1];

    //注入array类型的属性值
    if (propValue.getClass().isArray()) {
        Class<?> requiredType = propValue.getClass().getComponentType();
        int arrayIndex = Integer.parseInt(lastKey);
        Object oldValue = null;
        try {
            if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
                oldValue = Array.get(propValue, arrayIndex);
            }
            Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
                    requiredType, ph.nested(tokens.keys.length));
            //获取集合类型属性的长度
            int length = Array.getLength(propValue);
            if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
                Class<?> componentType = propValue.getClass().getComponentType();
                Object newArray = Array.newInstance(componentType, arrayIndex + 1);
                System.arraycopy(propValue, 0, newArray, 0, length);
                setPropertyValue(tokens.actualName, newArray);
                //调用属性的getter(readerMethod)方法,获取属性的值
                propValue = getPropertyValue(tokens.actualName);
            }
            //将属性的值赋值给数组中的元素
            Array.set(propValue, arrayIndex, convertedValue);
        }
        catch (IndexOutOfBoundsException ex) {
            throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
                    "Invalid array index in property path '" + tokens.canonicalName + "'", ex);
        }
    }

    //注入list类型的属性值
    else if (propValue instanceof List) {
        //获取list集合的类型
        Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
        List<Object> list = (List<Object>) propValue;
        //获取list集合的size
        int index = Integer.parseInt(lastKey);
        Object oldValue = null;
        if (isExtractOldValueForEditor() && index < list.size()) {
            oldValue = list.get(index);
        }
        //获取list解析后的属性值
        Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
                requiredType, ph.nested(tokens.keys.length));
        int size = list.size();
        //如果list的长度大于属性值的长度,则多余的元素赋值为null
        if (index >= size && index < this.autoGrowCollectionLimit) {
            for (int i = size; i < index; i++) {
                try {
                    list.add(null);
                }
                catch (NullPointerException ex) {
                    throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
                            "Cannot set element with index " + index + " in List of size " +
                            size + ", accessed using property path '" + tokens.canonicalName +
                            "': List does not support filling up gaps with null elements");
                }
            }
            list.add(convertedValue);
        }
        else {
            try {
                //将值添加到list中
                list.set(index, convertedValue);
            }
            catch (IndexOutOfBoundsException ex) {
                throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
                        "Invalid list index in property path '" + tokens.canonicalName + "'", ex);
            }
        }
    }

    //注入map类型的属性值
    else if (propValue instanceof Map) {
        //获取map集合key的类型
        Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
        //获取map集合value的类型
        Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);
        Map<Object, Object> map = (Map<Object, Object>) propValue;
        // IMPORTANT: Do not pass full property name in here - property editors
        // must not kick in for map keys but rather only for map values.
        TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
        //解析map类型属性key值
        Object convertedMapKey = convertIfNecessary(null, null, lastKey, mapKeyType, typeDescriptor);
        Object oldValue = null;
        if (isExtractOldValueForEditor()) {
            oldValue = map.get(convertedMapKey);
        }
        // Pass full property name and old value in here, since we want full
        // conversion ability for map values.
        //解析map类型属性value值
        Object convertedMapValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
                mapValueType, ph.nested(tokens.keys.length));
        //将解析后的key和value值赋值给map集合属性
        map.put(convertedMapKey, convertedMapValue);
    }

    else {
        throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
                "Property referenced in indexed property path '" + tokens.canonicalName +
                "' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
    }
}

private Object getPropertyHoldingValue(PropertyTokenHolder tokens) {
    // Apply indexes and map keys: fetch value for all keys but the last one.
    Assert.state(tokens.keys != null, "No token keys");
    PropertyTokenHolder getterTokens = new PropertyTokenHolder(tokens.actualName);
    getterTokens.canonicalName = tokens.canonicalName;
    getterTokens.keys = new String[tokens.keys.length - 1];
    System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);

    Object propValue;
    try {
        //获取属性值
        propValue = getPropertyValue(getterTokens);
    }
    catch (NotReadablePropertyException ex) {
        throw new NotWritablePropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
                "Cannot access indexed value in property referenced " +
                "in indexed property path '" + tokens.canonicalName + "'", ex);
    }

    if (propValue == null) {
        // null map value case
        if (isAutoGrowNestedPaths()) {
            int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
            getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
            propValue = setDefaultValue(getterTokens);
        }
        else {
            throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + tokens.canonicalName,
                    "Cannot access indexed value in property referenced " +
                    "in indexed property path '" + tokens.canonicalName + "': returned null");
        }
    }
    return propValue;
}

通过对上面注入依赖代码的分析,我们已经明白了Spring IOC容器是如何将属性的值注入到 Bean 实例对象中去的:
(1).对于集合类型的属性,将其属性值解析为目标类型的集合后直接赋值给属性。
(2).对于非集合类型的属性,大量使用了JDK的反射和内省机制,通过属性的 getter 方法(readerMethod)获取指定属性注入以前的值,同时调用属性的 setter 方法(writerMethod)为属性设置注入后的值。看到这里相信很多人都明白了 Spring 的setter注入原理。

下面基于XML依赖注入的时序图:

这里写图片描述

至此 Spring IOC 容器对Bean定义资源文件的定位,载入、解析和依赖注入已经全部分析完毕,现在Spring IOC容器中管理了一系列靠依赖关系联系起来的Bean,程序不需要应用自己手动创建所需的对象,Spring IOC容器会在我们使用的时候自动为我们创建,并且为我们注入好相关的依赖,这就是Spring 核心功能的控制反转和依赖注入的相关功能。

Spring5源码分析(三) IOC容器的依赖注入—基于XML的依赖注入 文章比较长所以分几篇来写,此篇为第三篇!也是最后一篇!

文档有参考其他资料,如果问题请联系我,进行删除!

需要原图请私信!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值