Spring源码深度解析(郝佳)-学习-源码解析(二)-自定义ConversionService

20 篇文章 1 订阅
18 篇文章 0 订阅

本文主要想要说明的是如何自定义类型转换器
我们先来做一个测试

User.java

@Data
public class User {
    private Date birth;
}

spring114.xml

<?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:mvc="http://www.springframework.org/schema/mvc"
       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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="user" class="com.spring_101_200.test_111_120.test_114_conversion2.User">
        <property name="birth" value="2019-03-22 24:12:13"></property>
    </bean>
    
</beans>

【结果输出】
Cannot convert value of type [java.lang.String] to required type [java.util.Date] for property ‘birth’: no matching editors or conversion strategy found

抛出异常,说无法将String类型转换成Date类型。

修改xml配置

<?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:mvc="http://www.springframework.org/schema/mvc"
       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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
	
   	<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
          <property name="converters">
              <list>
                   <bean class="com.spring_101_200.test_111_120.test_114_conversion2.String2DateConverter"></bean>
               </list>
          </property>
    </bean>

    <bean id="user" class="com.spring_101_200.test_111_120.test_114_conversion2.User">
        <property name="birth" value="2019-03-22 24:12:13"></property>
    </bean>
   
</beans>

【结果输出】
{“birth”:1553271133000}

首先,我们来看看conversionService Bean的解析。

BeanDefinitionParserDelegate.java

/**
 * 详细对元素中配置的Bean定义的其他的属性进行解析
 * 由于上面的方法已经对Bean的id,name和别名属性进行了处理
 * 该方法主要是处理除了这三个以外的其他的属性
 * 【注意】在解析<bean>元素的过程中没有创建和实例化<bean>对象,只是创建了Bean元素的定义类BeanDefinition,将<bean>元素中的信息
 * 设置到了BeanDefinition中作为记录,当依赖注入时才使用这些记录信息创建和实例化具体的Bean对象
 * 在对一些配置(如meta,qualifier等)的解析,我们在Spring中使用得不多,在使用Spring<Bean>元素时,配置最多的就是子元素
 */
public AbstractBeanDefinition parseBeanDefinitionElement(
        Element ele, String beanName, BeanDefinition containingBean) {
    LogUtils.all("parseBeanDefinitionElement beanName " + beanName);
    // 记录解析元素
    this.parseState.push(new BeanEntry(beanName));
    // 这里只读取元素中配置的class名字,然后载入BeanDefinition中
    // 只是记录配置的class名字,不做实例化,对象的实例化在依赖注入的时候完成
    String className = null;
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
   
    try {
        String parent = null;
        // 如果元素中配置了parent属性,则获取 parent属性的值
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }
        // 根据元素配置的class名称和parent属性值创建BeanDefinition
        // 为载入的Bean定义信息做准备
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);
        // 对当前的元素中配置的一些属性进行解析和设置,如果配置了单态(singleton)属性等
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        // 为<bean>元素解析的Bean设备描述信息
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
        // 为<bean>元素的meta(元信息进行解析)
        parseMetaElements(ele, bd);
        // 为<bean>元素的lookup-Method属性进行解析
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        // 为<bean>元素的replaced-Method属性进行解析
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
        //解析<bean>元素构造方法设置
        parseConstructorArgElements(ele, bd);
        //解析<bean>元素的设置
        parsePropertyElements(ele, bd);
        // 解析<bean>元素的qualifier属性
        parseQualifierElements(ele, bd);
        // 为当前的解析了Bean设置所需要的资源和依赖对象
        bd.setResource(this.readerContext.getResource());
        bd.setSource(extractSource(ele));
        return bd;
    } catch (ClassNotFoundException ex) {
        error("Bean class [" + className + "] not found", ele, ex);
    } catch (NoClassDefFoundError err) {
        error("Class that bean class [" + className + "] depends on not found", ele, err);
    } catch (Throwable ex) {
        error("Unexpected failure during bean definition parsing", ele, ex);
    } finally {
        this.parseState.pop();
    }
    // 当前解析元素出错时,返回null
    return null;
}

BeanDefinitionParserDelegate.java

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    // 获取元素中的所有的子元素
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        // 如果子元素中元素的子元素,则调用解析子元素的方法解析
        if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
            parsePropertyElement((Element) node, bd);
        }
    }
}

BeanDefinitionParserDelegate.java

/**
 * 解析元素
 */
public void parsePropertyElement(Element ele, BeanDefinition bd) {
    // 获取元素的名字
    String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
    if (!StringUtils.hasLength(propertyName)) {
        error("Tag 'property' must have a 'name' attribute", ele);
        return;
    }
    this.parseState.push(new PropertyEntry(propertyName));
    try {
        // 如果一个Bean中已经存在同名的元素存在,则不进行解析,直接返回
        // 即如果存在同一个Bean中配置同名的元素,则只有第一个起作用
        if (bd.getPropertyValues().contains(propertyName)) {
            error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
            return;
        }
        //解析获取的元素的值
        Object val = parsePropertyValue(ele, bd, propertyName);
        //根据元素的名字和值创建实例
        PropertyValue pv = new PropertyValue(propertyName, val);
        //解析元素中的meta属性
        parseMetaElements(ele, pv);
        pv.setSource(extractSource(ele));
        bd.getPropertyValues().addPropertyValue(pv);
    } finally {
        this.parseState.pop();
    }
}

BeanDefinitionParserDelegate.java

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
    String elementName = (propertyName != null) ?
            " element for property '" + propertyName + "'" :
            " element";
    // 获取中的所有的子元素,只能是ref,value,list,etc中的一种类型
    NodeList nl = ele.getChildNodes();
    Element subElement = null;
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        // 子元素是description和meta属性 不做处理
        if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
                !nodeNameEquals(node, META_ELEMENT)) {
            if (subElement != null) {
                error(elementName + " must not contain more than one sub-element", ele);
            } else {
                // 当property元素包含子元素
                subElement = (Element) node;
            }
        }
    }
    // 解析constructor-arg 的ref 属性
    boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
    // 解析constructor-arg 上的value属性
    boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
    // 判断属性值是ref还是value,不允许既是ref 又是value
    if ((hasRefAttribute && hasValueAttribute) ||
            ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
        /**
         * 在constructor-arg上不存在:
         * 1.同时既有ref属性又有value属性
         * 2.存在ref属性或者value属性且又有子元素
         */
        error(elementName +
                " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
    }
    // 如果属性值是ref ,创建一个ref 的数据对象,RuntimeBeanReference,这个对象封装了ref
    if (hasRefAttribute) {
        String refName = ele.getAttribute(REF_ATTRIBUTE);
        if (!StringUtils.hasText(refName)) {

            error(elementName + " contains empty 'ref' attribute", ele);
        }
        //ref属性的处理,使用RuntimeBeanReference封装对应的ref名称
        RuntimeBeanReference ref = new RuntimeBeanReference(refName);
        ref.setSource(extractSource(ele));
        return ref;
        // 如果属性值是value,创建一个value数据对象,typedStringValue,这个对象封装了value
    } else if (hasValueAttribute) {
        // 一个持有String类型的对象
        TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
        // 设置这个value的数据对象被当前对象所引用
        valueHolder.setSource(extractSource(ele));
        return valueHolder;
    } else if (subElement != null) {
        // 解析子元素
        return parsePropertySubElement(subElement, bd);
    } else {
        // 属性值既不是ref也不是value,解析出错,返回null
        error(elementName + " must specify a ref or value", ele);
        return null;
    }
}

BeanDefinitionParserDelegate.java

public Object parsePropertySubElement(Element ele, BeanDefinition bd) {
	return parsePropertySubElement(ele, bd, null);
}

BeanDefinitionParserDelegate.java

 /**
 *                         {@code <value>} tag that might be created
 *                         解析<property>元素中的ref,value或者集合等元素
 * 通过下面的源码可以得到,在Spring配置文件中,对<property>元素中的配置的<array>,<list>,<set>,<map>,<props>,等各种子元素都
 *                         通过上面的方法解析,生成对应的数据对象,比如ManagedList,ManagedArray,ManagedSet,等,这些managed类是
 *                         Spring对象的BeanDefinition的数据封装,对集合数据类型的具体解析由各种解析方法实现,解析方法的命名也非常的
 *                         一目了然
 * 经过对Spring Bean配置信息转换文档对象中的元素层层解析,Spring Ioc现在已经将XML 形式定义的Bean配置信息转换为Spring Ioc所识别的数据
 * 结构,BeanDefinition,它是Bean配置信息中的POJO对象在Spring IOC容器中的映射,我们通过AbstractBeanDefinition作为入口,
 *                         看如何在Spring Ioc容器进行索引,查询,和其他的操作
 *                         通过Spring Ioc容器对Bean 的配置信息的解析,    Spring IOc 容器大致完成了Bean 对象的唯一的准备工作
 *                         ,即初始化过程,但是最的重要的依赖注入还没有发生,在Spring Ioc容器中BeanDefinition在存储的还是一些静态的
 *                         信息,接下来,需要向容器注册Bean定义信息,才能真正的完成IOC容器的初始化工作
 */
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
    // 如果<property>元素没有使用Spring默认的命名空间,则使用用户自定义的规则解析内嵌元素
    if (!isDefaultNamespace(ele)) {
        return parseNestedCustomElement(ele, bd);
        //如果子元素是Bean,则使用解析<bean>元素的方法解析
    } else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
        BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
        if (nestedBd != null) {
            nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
        }
        return nestedBd;
        //如果子元素是ref,ref只能有3个属性,bean,local,parent
    } else if (nodeNameEquals(ele, REF_ELEMENT)) {
        // A generic reference to any name of any bean.
        // 可以不在同一个Spring配置文件中上,具体参考 Spring 对ref配置规则
        String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
        boolean toParent = false;
        if (!StringUtils.hasLength(refName)) {
            // A reference to the id of another bean in the same XML file.
            //解析local
            refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
            if (!StringUtils.hasLength(refName)) {
                // A reference to the id of another bean in a parent context.
                //  获取元素中的parent属性值,引用父容器中的Bean
                refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
                toParent = true;
                if (!StringUtils.hasLength(refName)) {
                    error("'bean', 'local' or 'parent' is required for  element", ele);
                    return null;
                }
            }
        }
        if (!StringUtils.hasText(refName)) {
            error(" element contains empty target attribute", ele);
            return null;
        }
        // 创建ref类型数据,指向被引用的对象
        RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
        //设置引用类型值被当前的子元素所引用
        ref.setSource(extractSource(ele));
        return ref;
        //如果子元素是,使用解析元素的方法进行解析
    } else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
        return parseIdRefElement(ele);
        //如果子元素是,使用解析元素的方法解析
    } else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
        return parseValueElement(ele, defaultValueType);
        //如果子元素是null,则为元素设置一个封装null值的字符串数据
    } else if (nodeNameEquals(ele, NULL_ELEMENT)) {
        TypedStringValue nullHolder = new TypedStringValue(null);
        nullHolder.setSource(extractSource(ele));
        return nullHolder;
        //如果子元素是,则使用解析集合元素的方法进行解析
    } else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
        return parseArrayElement(ele, bd);
        //如果子元素是,则使用解析元素的方法进行解析
    } else if (nodeNameEquals(ele, LIST_ELEMENT)) {
        return parseListElement(ele, bd);
        //如果子元素是,则使用集合子元素的方法解析
    } else if (nodeNameEquals(ele, SET_ELEMENT)) {
        return parseSetElement(ele, bd);
        // 如果子元素是,则使用集合中的元素方法进行解析
    } else if (nodeNameEquals(ele, MAP_ELEMENT)) {
        return parseMapElement(ele, bd);
        //如果子元素是,则使用集合元素中的方法进行解析
    } else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
        return parsePropsElement(ele);
        //如果既不是ref又不是value,也不是集合,则说明子元素配置错误,返回null
    } else {
        error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
        return null;
    }
}

BeanDefinitionParserDelegate.java

/**
 * Parse a list element.
 * 解析集合元素
 */
public List parseListElement(Element collectionEle, BeanDefinition bd) {
    //获取元素中的value-type属性,即获取集合元素中的数据类型
    String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
    //获取元素中的所有的集合结点
    NodeList nl = collectionEle.getChildNodes();
    //Spring中将list封装成ManagedList
    ManagedList target = new ManagedList(nl.getLength());
    target.setSource(extractSource(collectionEle));
    //设置集合目标的数据类型
    target.setElementTypeName(defaultElementType);

    target.setMergeEnabled(parseMergeAttribute(collectionEle));
    //具体的<list>元素的解析
    parseCollectionElements(nl, target, bd, defaultElementType);
    return target;
}

BeanDefinitionParserDelegate.java

//具体的解析<list>集合子元素,<array>,<list>和<set>都使用了方法解析
protected void parseCollectionElements(
        NodeList elementNodes, Collection target, BeanDefinition bd, String defaultElementType) {
    // 遍历集合的所有的了节点
    for (int i = 0; i < elementNodes.getLength(); i++) {
        Node node = elementNodes.item(i);
        //节点不是description节点
        if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {
            //将解析的元素加入到集合,递归调用下一个元素
            target.add(parsePropertySubElement((Element) node, bd, defaultElementType));
        }
    }
}

递归调用parsePropertySubElement方法来解析

BeanDefinitionParserDelegate.java

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    // 获取<bean>元素中的id属性值
    String id = ele.getAttribute(ID_ATTRIBUTE);
    // 获取<bean>元素的name属性值
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    LogUtils.info("parseBeanDefinitionElement id " + id + " nameAttr " + nameAttr);
    // 获取bean元素的alias属性值 
    List aliases = new ArrayList();
    // 将<bean>元素的中的所有alias属性值放入到别名中
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }
    String beanName = id;
    // 如果<bean>元素中没有配置id属性,将别名中的第一个值赋值给beanName
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        beanName = aliases.remove(0);
        if (logger.isDebugEnabled()) {
            logger.debug("No XML 'id' specified - using '" + beanName +
                    "' as bean name and " + aliases + " as aliases");
        }
    }
    // 检查<bean>元素所配置的id或者name唯一性
    if (containingBean == null) {
        //检查<bean>元素的所配置的id,name或者别名是否重复
        checkNameUniqueness(beanName, aliases, ele);
    }
    // 详细对<bean>元素中的配置的bean定义进行解析
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                if (containingBean != null) {
                    // 如果<bean>元素中没有配置id,别名或者name,且没有包含子元素
                    // 元素,则解析的Bean生成一个唯一的beanName并注册
                    beanName = BeanDefinitionReaderUtils.generateBeanName(
                            beanDefinition, this.readerContext.getRegistry(), true);
                } else {
                    // 如果<bean>元素没有配置id,别名或者name,且包含子元素
                    // 元素,则将解析的Bean生成一个唯一的BeanName并注册
                    beanName = this.readerContext.generateBeanName(beanDefinition);
                    String beanClassName = beanDefinition.getBeanClassName();
                    // 为解析的Bean使用别名注册时,为了向后兼容
                    // Spring 1.2 /2.0 给别名添加后缀
                    if (beanClassName != null &&
                            beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                            !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                        aliases.add(beanClassName);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Neither XML 'id' nor 'name' specified - " +
                            "using generated bean name [" + beanName + "]");
                }
            } catch (Exception ex) {
                error(ex.getMessage(), ele);
                return null;
            }
        }
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }
    // 当解析出错时,返回null
    return null;
}

public static String generateBeanName(
		BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
		throws BeanDefinitionStoreException {

	String generatedBeanName = definition.getBeanClassName();
	if (generatedBeanName == null) {
		if (definition.getParentName() != null) {
			generatedBeanName = definition.getParentName() + "$child";
		}
		else if (definition.getFactoryBeanName() != null) {
			generatedBeanName = definition.getFactoryBeanName() + "$created";
		}
	}
	if (!StringUtils.hasText(generatedBeanName)) {
		throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
				"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
	}

	String id = generatedBeanName;
	if (isInnerBean) {
		// Inner bean: generate identity hashcode suffix.
		id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
	}
	else {
		// Top-level bean: use plain class name.
		// Increase counter until the id is unique.
		int counter = -1;
		while (counter == -1 || registry.containsBeanDefinition(id)) {
			counter++;
			id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
		}
	}
	return id;
}

最终我们在解析子元素时得到了String2DateConverter的BeanDefinitionHolder,并且保存到了ManagedList中
在这里插入图片描述
关于User对象的解析,以相同的方式来解析,这里将不再缀述。最终将得到的BeanDefinition保存到beanDefinitionMap中。元素己经解析完成,下面,我们来分析属性封装。

AbstractAutowireCapableBeanFactory.java

/**
 *            解析并注入依赖属性的过程
 *            从这个代码中可以看出,属性的注入过程分成以下的两种情况
 *            1.属性值的类型不需要强制转换时,不需要解析属性值进,直接进行依赖注入
 *            2.属性类型需要进行强制转换时,如对其他的对象引用等,首先需要解析属性值,然后对解析后的属性进行依赖注入
 *            对属性的解析是在BeanDefinitionValueResolver类的resolverValueNecessary()方法中进行的的,对属性值的依赖注入是通过
 *            bw.setPropertyValues()方法来实现
 *
 *
 *            程序运行到这里已经完成了对所有的注入属性的获取,但是获取 属性是以 PropertyValues 的形式存在,还并没有应用到
 *            已经实例化的 bean 中,这一工作是在 applyPropertyValues 中
 */
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
	if (pvs == null || pvs.isEmpty()) {
		return;
	}
	// 封装属性值
	MutablePropertyValues mpvs = null;
	List original;

	if (System.getSecurityManager() != null) {
		if (bw instanceof BeanWrapperImpl) {
			// 设置安全上下文,jdk安全机制
			((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
		}
	}

	if (pvs instanceof MutablePropertyValues) {
		mpvs = (MutablePropertyValues) pvs;
		// 如果 mpv 中的值已经被转换成对应的类类型,那么可以直接设置到 beanWrapper 中
		if (mpvs.isConverted()) {
			// Shortcut: use the pre-converted values as-is.
			try {
				// 为实例化对象设置属性值
				bw.setPropertyValues(mpvs);
				return;
			}
			catch (BeansException ex) {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Error setting property values", ex);
			}
		}
		// 获取属性值对象的原始类型值
		original = mpvs.getPropertyValueList();
	}
	else {
		// 如果 pvs 并不是使用 MutablePropertyValues 封装类型,那么直接使用原始的属性获取方法
		original = Arrays.asList(pvs.getPropertyValues());
	}
	//获取用户自定义类型转换
	TypeConverter converter = getCustomTypeConverter();
	if (converter == null) {
		converter = bw;
	}
	// 创建一个Bean定义属性值解析器,将Bean定义中的属性值解析为Bean实例对象的实际值 
	BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

	// 为属性解析创建一个副本,将副本数据注入实例对象
	List deepCopy = new ArrayList(original.size());
	boolean resolveNecessary = false;
	// 遍历属性,将属性转换为对应的类的对应的属性类型
	for (PropertyValue pv : original) {
		// 属性值不需要转换
		if (pv.isConverted()) {
			deepCopy.add(pv);
		}
		// 属性值需要转换
		else {
			String propertyName = pv.getName();
			// 原始属性值,即转换之前的属性值
			Object originalValue = pv.getValue();
			// 转换的属性值,例如将引用转换成Ioc容器中的实例化对象的引用
			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);
			}

			// 存储转换之后的属性值,避免每次属性注入的时候转换工作
			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 {
		bw.setPropertyValues(new MutablePropertyValues(deepCopy));
	}
	catch (BeansException ex) {
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Error setting property values", ex);
	}
}

BeanDefinitionValueResolver.java

/**
 *	容器对属性进行依赖注入时,如果发现属性需要进行类型转换,例如属性值是容器中另一个Bean实例对象的引用,则容器首先需要根据属性值
 *进行解析出所引用的对象,然后,才能将该引用的对象注入到目标实例的属性上,对属性的解析由resolveValueIfNecessary()方法的实现,其源码
 * 如下
 * 解析属性值,对注入类型的进行转换
 * 通过下面的代码分析,我们明白了Spring 是如何通过引用类型,内部类及集合类型的属性进行分析的,解析完成之后,就可以进行依赖注入了
 * ,依赖注入的过程就是将Bean对象实例设置到它们所依赖的Bean的属性上,真正的依赖注入是通过bw.setPropertyValues()方法实现的,
 * 该方法也使用了委派模式,在BeanWrapper接口中定义了方法声明,依赖注入的具体的实现交由其实现类BeanWrapperImpl完成的,
 * 下面我们根据BeanWrappperImpl类中依赖注入相关的代码来完成
 */

public Object resolveValueIfNecessary(Object argName, Object value) {
	// 对引用类型的属性值进行解析
	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) {
		BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
		return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
	}

	else if (value instanceof BeanDefinition) {
		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) {
		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) {
					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) {
		return resolveManagedList(argName, (List<?>) value);
	}
	// 解析set类型的属性值
	else if (value instanceof ManagedSet) {
		return resolveManagedSet(argName, (Set<?>) value);
	}
	// 解析map类型的属性值
	else if (value instanceof ManagedMap) {
		return resolveManagedMap(argName, (Map<?, ?>) value);
	}
	// 解析props类型的属性值,props其实就是key 和value均为字符串的map
	else if (value instanceof ManagedProperties) {
		Properties original = (Properties) value;
		// 创建一个副本,作为解析后的返回值
		Properties copy = new Properties();
		for (Map.Entry<Object, Object> propEntry : original.entrySet()) {
			Object propKey = propEntry.getKey();
			Object propValue = propEntry.getValue();
			if (propKey instanceof TypedStringValue) {
				propKey = evaluate((TypedStringValue) propKey);
			}
			if (propValue instanceof TypedStringValue) {
				propValue = evaluate((TypedStringValue) propValue);
			}
			copy.put(propKey, propValue);
		}
		return copy;
	}
	// 解析字符串类型的属性值
	else if (value instanceof TypedStringValue) {
		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) {
			throw new BeanCreationException(
					this.beanDefinition.getResourceDescription(), this.beanName,
					"Error converting typed String value for " + argName, ex);
		}
	}
	else {
		return evaluate(value);
	}
}

BeanDefinitionValueResolver.java

public Object resolveValueIfNecessary(Object argName, Object value) {
private List<?> resolveManagedList(Object argName, List<?> ml) {
	List resolved = new ArrayList(ml.size());
	for (int i = 0; i < ml.size(); i++) {
		resolved.add(
				resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i)));
	}
	return resolved;
}

BeanDefinitionValueResolver.java

private Object resolveInnerBean(Object argName, String innerBeanName, BeanDefinition innerBd) {
	RootBeanDefinition mbd = null;
	try {
		mbd = this.beanFactory.getMergedBeanDefinition(innerBeanName, innerBd, this.beanDefinition);
		// Check given bean name whether it is unique. If not already unique,
		// add counter - increasing the counter until the name is unique.
		String actualInnerBeanName = innerBeanName;
		if (mbd.isSingleton()) {
			actualInnerBeanName = adaptInnerBeanName(innerBeanName);
		}
		this.beanFactory.registerContainedBean(actualInnerBeanName, this.beanName);
		// Guarantee initialization of beans that the inner bean depends on.
		String[] dependsOn = mbd.getDependsOn();
		if (dependsOn != null) {
			for (String dependsOnBean : dependsOn) {
				this.beanFactory.registerDependentBean(dependsOnBean, actualInnerBeanName);
				this.beanFactory.getBean(dependsOnBean);
			}
		}
		// Actually create the inner bean instance now...
		Object innerBean = this.beanFactory.createBean(actualInnerBeanName, mbd, null);
		if (innerBean instanceof FactoryBean) {
			boolean synthetic = mbd.isSynthetic();
			return this.beanFactory.getObjectFromFactoryBean(
					(FactoryBean<?>) innerBean, actualInnerBeanName, !synthetic);
		}
		else {
			return innerBean;
		}
	}
	catch (BeansException ex) {
		throw new BeanCreationException(
				this.beanDefinition.getResourceDescription(), this.beanName,
				"Cannot create inner bean '" + innerBeanName + "' " +
				(mbd != null && mbd.getBeanClassName() != null ? "of type [" + mbd.getBeanClassName() + "] " : "") +
				"while setting " + argName, ex);
	}
}

代码运行到这里,因此resolveValueIfNecessary方法己经得到 了Conversion 的List 集合 。
在这里插入图片描述
isWritableProperty方法特别重要,这里,他得到了ConversionServiceFactoryBean的BeanInfo,及其PropertyDescriptor并保存到了缓存中。也就是说,得到了converters的类型为java.util.Set类型,并保存到缓存中,方便类型转换。

AbstractAutowireCapableBeanFactory.java

private Object convertForProperty(Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
	if (converter instanceof BeanWrapperImpl) {
		return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
	}
	else {
		PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
		MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
		return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
	}
}

BeanWrapperImpl.java

public Object convertForProperty(Object value, String propertyName) throws TypeMismatchException {
	CachedIntrospectionResults cachedIntrospectionResults = getCachedIntrospectionResults();
	PropertyDescriptor pd = cachedIntrospectionResults.getPropertyDescriptor(propertyName);
	if (pd == null) {
		throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
				"No property '" + propertyName + "' found");
	}
	TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
	if (td == null) {
		td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd)));
	}
	return convertForProperty(propertyName, null, value, td);
}

从缓存中获取到td 的类型为java.utils.Set
在这里插入图片描述

AbstractNestablePropertyAccessor.java

protected Object convertForProperty(String propertyName, Object oldValue, Object newValue, TypeDescriptor td)
		throws TypeMismatchException {

	return convertIfNecessary(propertyName, oldValue, newValue, td.getType(), td);
}

AbstractNestablePropertyAccessor.java

private Object convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<?> requiredType,
		TypeDescriptor td) throws TypeMismatchException {
	try {
		return this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td);
	}
	catch (ConverterNotFoundException ex) {
		PropertyChangeEvent pce =
				new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
		throw new ConversionNotSupportedException(pce, td.getType(), ex);
	}
}

TypeConverterDelegate.java

public  T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
		Class requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {

	// Custom editor for this type?
	PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);

	ConversionFailedException conversionAttemptEx = null;

	// No custom editor but custom ConversionService specified?
	ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
	if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
		TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
		if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
			try {
				return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
			}
			catch (ConversionFailedException ex) {
				// fallback to default conversion logic below
				conversionAttemptEx = ex;
			}
		}
	}

	Object convertedValue = newValue;

	// Value not of required type?
	if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
		if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String) {
			TypeDescriptor elementType = typeDescriptor.getElementTypeDescriptor();
			if (elementType != null && Enum.class.isAssignableFrom(elementType.getType())) {
				convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
			}
		}
		if (editor == null) {
			editor = findDefaultEditor(requiredType);
		}
		convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
	}

	boolean standardConversion = false;

	if (requiredType != null) {
		// Try to apply some standard type conversion rules if appropriate.

		if (convertedValue != null) {
			if (Object.class == requiredType) {
				return (T) convertedValue;
			}
			else if (requiredType.isArray()) {
				// Array required -> apply appropriate conversion of elements.
				if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
					convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
				}
				return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
			}
			else if (convertedValue instanceof Collection) {
				// Convert elements to target type, if determined.
				convertedValue = convertToTypedCollection(
						(Collection<?>) convertedValue, propertyName, requiredType, typeDescriptor);
				standardConversion = true;
			}
			else if (convertedValue instanceof Map) {
				// Convert keys and values to respective target type, if determined.
				convertedValue = convertToTypedMap(
						(Map<?, ?>) convertedValue, propertyName, requiredType, typeDescriptor);
				standardConversion = true;
			}
			if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
				convertedValue = Array.get(convertedValue, 0);
				standardConversion = true;
			}
			if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
				// We can stringify any primitive value...
				return (T) convertedValue.toString();
			}
			else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
				if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
					try {
						Constructor strCtor = requiredType.getConstructor(String.class);
						return BeanUtils.instantiateClass(strCtor, convertedValue);
					}
					catch (NoSuchMethodException ex) {
						// proceed with field lookup
						if (logger.isTraceEnabled()) {
							logger.trace("No String constructor found on type [" + requiredType.getName() + "]", ex);
						}
					}
					catch (Exception ex) {
						if (logger.isDebugEnabled()) {
							logger.debug("Construction via String failed for type [" + requiredType.getName() + "]", ex);
						}
					}
				}
				String trimmedValue = ((String) convertedValue).trim();
				if (requiredType.isEnum() && "".equals(trimmedValue)) {
					// It's an empty enum identifier: reset the enum value to null.
					return null;
				}
				convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
				standardConversion = true;
			}
			else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
				convertedValue = NumberUtils.convertNumberToTargetClass(
						(Number) convertedValue, (Class) requiredType);
				standardConversion = true;
			}
		}
		else {
			// convertedValue == null
			if (javaUtilOptionalEmpty != null && requiredType.equals(javaUtilOptionalEmpty.getClass())) {
				convertedValue = javaUtilOptionalEmpty;
			}
		}

		if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
			if (conversionAttemptEx != null) {
				// Original exception from former ConversionService call above...
				throw conversionAttemptEx;
			}
			else if (conversionService != null) {
				// ConversionService not tried before, probably custom editor found
				// but editor couldn't produce the required type...
				TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
				if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
					return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
				}
			}

			// Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
			StringBuilder msg = new StringBuilder();
			msg.append("Cannot convert value of type [").append(ClassUtils.getDescriptiveType(newValue));
			msg.append("] to required type [").append(ClassUtils.getQualifiedName(requiredType)).append("]");
			if (propertyName != null) {
				msg.append(" for property '").append(propertyName).append("'");
			}
			if (editor != null) {
				msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
						"] returned inappropriate value of type [").append(
						ClassUtils.getDescriptiveType(convertedValue)).append("]");
				throw new IllegalArgumentException(msg.toString());
			}
			else {
				msg.append(": no matching editors or conversion strategy found");
				throw new IllegalStateException(msg.toString());
			}
		}
	}

	if (conversionAttemptEx != null) {
		if (editor == null && !standardConversion && requiredType != null && Object.class != requiredType) {
			throw conversionAttemptEx;
		}
		logger.debug("Original ConversionService attempt failed - ignored since " +
				"PropertyEditor based conversion eventually succeeded", conversionAttemptEx);
	}

	return (T) convertedValue;
}

TypeConverterDelegate.java

private Object doConvertValue(Object oldValue, Object newValue, Class<?> requiredType, PropertyEditor editor) {
	Object convertedValue = newValue;

	if (editor != null && !(convertedValue instanceof String)) {
		// Not a String -> use PropertyEditor's setValue.
		// With standard PropertyEditors, this will return the very same object;
		// we just want to allow special PropertyEditors to override setValue
		// for type conversion from non-String values to the required type.
		try {
			editor.setValue(convertedValue);
			Object newConvertedValue = editor.getValue();
			if (newConvertedValue != convertedValue) {
				convertedValue = newConvertedValue;
				// Reset PropertyEditor: It already did a proper conversion.
				// Don't use it again for a setAsText call.
				editor = null;
			}
		}
		catch (Exception ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("PropertyEditor [" + editor.getClass().getName() + "] does not support setValue call", ex);
			}
			// Swallow and proceed.
		}
	}

	Object returnValue = convertedValue;

	if (requiredType != null && !requiredType.isArray() && convertedValue instanceof String[]) {
		// Convert String array to a comma-separated String.
		// Only applies if no PropertyEditor converted the String array before.
		// The CSV String will be passed into a PropertyEditor's setAsText method, if any.
		if (logger.isTraceEnabled()) {
			logger.trace("Converting String array to comma-delimited String [" + convertedValue + "]");
		}
		convertedValue = StringUtils.arrayToCommaDelimitedString((String[]) convertedValue);
	}

	if (convertedValue instanceof String) {
		if (editor != null) {
			// Use PropertyEditor's setAsText in case of a String value.
			if (logger.isTraceEnabled()) {
				logger.trace("Converting String to [" + requiredType + "] using property editor [" + editor + "]");
			}
			String newTextValue = (String) convertedValue;
			return doConvertTextValue(oldValue, newTextValue, editor);
		}
		else if (String.class == requiredType) {
			returnValue = convertedValue;
		}
	}

	return returnValue;
}

由于我们得到的转换器是CustomCollectionEditor,因此调用CustomCollectionEditor的setValue方法。
在这里插入图片描述

CustomCollectionEditor.java

public void setValue(Object value) {
	if (value == null && this.nullAsEmptyCollection) {
		super.setValue(createCollection(this.collectionType, 0));
	}
	else if (value == null || (this.collectionType.isInstance(value) && !alwaysCreateNewCollection())) {
		// Use the source value as-is, as it matches the target type.
		super.setValue(value);
	}
	else if (value instanceof Collection) {
		// Convert Collection elements.
		Collection<?> source = (Collection<?>) value;
		Collection target = createCollection(this.collectionType, source.size());
		for (Object elem : source) {
			target.add(convertElement(elem));
		}
		super.setValue(target);
	}
	else if (value.getClass().isArray()) {
		// Convert array elements to Collection elements.
		int length = Array.getLength(value);
		Collection target = createCollection(this.collectionType, length);
		for (int i = 0; i < length; i++) {
			target.add(convertElement(Array.get(value, i)));
		}
		super.setValue(target);
	}
	else {
		// A plain value: convert it to a Collection with a single element.
		Collection target = createCollection(this.collectionType, 1);
		target.add(convertElement(value));
		super.setValue(target);
	}
}

CustomCollectionEditor.java

protected Collection createCollection(Class<? extends Collection> collectionType, int initialCapacity) {
	if (!collectionType.isInterface()) {
		try {
			return collectionType.newInstance();
		}
		catch (Exception ex) {
			throw new IllegalArgumentException(
					"Could not instantiate collection class [" + collectionType.getName() + "]: " + ex.getMessage());
		}
	}
	else if (List.class == collectionType) {
		return new ArrayList(initialCapacity);
	}
	else if (SortedSet.class == collectionType) {
		return new TreeSet();
	}
	else {
		return new LinkedHashSet(initialCapacity);
	}
}

到这里己经得到了LinkedHashSet,并将String2DateConverter对象保存到LinkedHashSet中。
那值又是如何设置进去的呢?我回到AbstractAutowireCapableBeanFactory的setPropertyValues方法。

AbstractPropertyAccessor.java

public void setPropertyValues(PropertyValues pvs) throws BeansException {
	setPropertyValues(pvs, false, false);
}

AbstractPropertyAccessor.java

@Override
public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
		throws BeansException {

	List propertyAccessExceptions = null;
	List 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 LinkedList();
			}
			propertyAccessExceptions.add(ex);
		}
	}

	// If we encountered individual exceptions, throw the composite exception.
	if (propertyAccessExceptions != null) {
		PropertyAccessException[] paeArray =
				propertyAccessExceptions.toArray(new PropertyAccessException[propertyAccessExceptions.size()]);
		throw new PropertyBatchUpdateException(paeArray);
	}
}

AbstractNestablePropertyAccessor.java

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);
	}
}


AbstractNestablePropertyAccessor.java

protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
	String propertyName = tokens.canonicalName;
	String actualName = tokens.actualName;

	if (tokens.keys != null) {
		// Apply indexes and map keys: fetch value for all keys but the last one.
		PropertyTokenHolder getterTokens = new PropertyTokenHolder();
		getterTokens.canonicalName = tokens.canonicalName;
		getterTokens.actualName = tokens.actualName;
		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 + propertyName,
					"Cannot access indexed value in property referenced " +
							"in indexed property path '" + propertyName + "'", ex);
		}
		// Set value for last key.
		String key = tokens.keys[tokens.keys.length - 1];
		if (propValue == null) {
			// null map value case
			if (isAutoGrowNestedPaths()) {
				// TODO: cleanup, this is pretty hacky
				int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
				getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
				propValue = setDefaultValue(getterTokens);
			}
			else {
				throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,
						"Cannot access indexed value in property referenced " +
								"in indexed property path '" + propertyName + "': returned null");
			}
		}
		if (propValue.getClass().isArray()) {
			PropertyHandler ph = getLocalPropertyHandler(actualName);
			Class<?> requiredType = propValue.getClass().getComponentType();
			int arrayIndex = Integer.parseInt(key);
			Object oldValue = null;
			try {
				if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
					oldValue = Array.get(propValue, arrayIndex);
				}
				Object convertedValue = convertIfNecessary(propertyName, 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(actualName, newArray);
					propValue = getPropertyValue(actualName);
				}
				Array.set(propValue, arrayIndex, convertedValue);
			}
			catch (IndexOutOfBoundsException ex) {
				throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
						"Invalid array index in property path '" + propertyName + "'", ex);
			}
		}
		else if (propValue instanceof List) {
			PropertyHandler ph = getPropertyHandler(actualName);
			Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
			List list = (List) propValue;
			int index = Integer.parseInt(key);
			Object oldValue = null;
			if (isExtractOldValueForEditor() && index < list.size()) {
				oldValue = list.get(index);
			}
			Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
					requiredType, ph.nested(tokens.keys.length));
			int size = list.size();
			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 + propertyName,
								"Cannot set element with index " + index + " in List of size " +
										size + ", accessed using property path '" + propertyName +
										"': List does not support filling up gaps with null elements");
					}
				}
				list.add(convertedValue);
			}
			else {
				try {
					list.set(index, convertedValue);
				}
				catch (IndexOutOfBoundsException ex) {
					throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
							"Invalid list index in property path '" + propertyName + "'", ex);
				}
			}
		}
		else if (propValue instanceof Map) {
			PropertyHandler ph = getLocalPropertyHandler(actualName);
			Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
			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);
			Object convertedMapKey = convertIfNecessary(null, null, key, 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.
			Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
					mapValueType, ph.nested(tokens.keys.length));
			map.put(convertedMapKey, convertedMapValue);
		}
		else {
			throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
					"Property referenced in indexed property path '" + propertyName +
							"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
		}
	}

	else {
		PropertyHandler ph = getLocalPropertyHandler(actualName);
		if (ph == null || !ph.isWritable()) {
			if (pv.isOptional()) {
				if (logger.isDebugEnabled()) {
					logger.debug("Ignoring optional value for property '" + actualName +
							"' - property not found on bean class [" + getRootClass().getName() + "]");
				}
				return;
			}
			else {
				throw createNotWritablePropertyException(propertyName);
			}
		}
		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) {
							if (ex instanceof PrivilegedActionException) {
								ex = ((PrivilegedActionException) ex).getException();
							}
							if (logger.isDebugEnabled()) {
								logger.debug("Could not read previous value of property '" +
										this.nestedPath + propertyName + "'", ex);
							}
						}
					}
					valueToApply = convertForProperty(
							propertyName, oldValue, originalValue, ph.toTypeDescriptor());
				}
				pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
			}
			ph.setValue(object, valueToApply);
		}
		catch (TypeMismatchException ex) {
			throw ex;
		}
		catch (InvocationTargetException ex) {
			PropertyChangeEvent propertyChangeEvent =
					new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, 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(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
			throw new MethodInvocationException(pce, ex);
		}
	}
}

BeanWrapperImpl.java

public void setValue(final Object object, Object valueToApply) throws Exception {
	final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
			((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
			this.pd.getWriteMethod());
	if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged(new PrivilegedAction() {
				@Override
				public Object run() {
					writeMethod.setAccessible(true);
					return null;
				}
			});
		}
		else {
			writeMethod.setAccessible(true);
		}
	}
	final Object value = valueToApply;
	if (System.getSecurityManager() != null) {
		try {
			AccessController.doPrivileged(new PrivilegedExceptionAction() {
				@Override
				public Object run() throws Exception {
					writeMethod.invoke(object, value);
					return null;
				}
			}, acc);
		}
		catch (PrivilegedActionException ex) {
			throw ex.getException();
		}
	}
	else {
		writeMethod.invoke(getWrappedInstance(), value);
	}
}

到这里终于通过反射将LinkedHashSet的值封装到了ConversionServiceFactoryBean的converters属性中。

类型转换器的解析,转换,属性设值己经完成,下面,我们真正值的转换过程。
我们又回到刚刚的convertIfNecessary方法。
在这里插入图片描述

GenericConversionService.java

@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
	Assert.notNull(targetType, "targetType to convert to cannot be null");
	if (sourceType == null) {
		Assert.isTrue(source == null, "source must be [null] if sourceType == [null]");
		return handleResult(null, targetType, convertNullSource(null, targetType));
	}
	if (source != null && !sourceType.getObjectType().isInstance(source)) {
		throw new IllegalArgumentException("source to convert from must be an instance of " +
				sourceType + "; instead it was a " + source.getClass().getName());
	}
	GenericConverter converter = getConverter(sourceType, targetType);
	if (converter != null) {
		Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
		return handleResult(sourceType, targetType, result);
	}
	return handleConverterNotFound(source, sourceType, targetType);
}

ConversionUtils.java

public static Object invokeConverter(GenericConverter converter, Object source, TypeDescriptor sourceType,
		TypeDescriptor targetType) {
	try {
		return converter.convert(source, sourceType, targetType);
	}
	catch (ConversionFailedException ex) {
		throw ex;
	}
	catch (Exception ex) {
		throw new ConversionFailedException(sourceType, targetType, source, ex);
	}
}

ConverterAdapter.java

@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
	if (source == null) {
		return convertNullSource(sourceType, targetType);
	}
	return this.converter.convert(source);
}

String2DateConverter.java

public class String2DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String arg0) {
         try {
              SimpleDateFormat simpleDateFormat  = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
              return simpleDateFormat.parse(arg0);
         } catch (ParseException e) {
              e.printStackTrace();
         }
         return null;
    }
}

终于看到了我们久纬的方法。自定义类型转换器。将字符串类型转换成Date类型。和converters注入一样,通过反射方法将值注入到User 的birth属性中。

到这里,我们终于完成了自定义属性的解析,注入,以后对象调用自定义属性转换器。
下面我们来总结一下。

  1. 我们先分析了ConversionServiceFactoryBean的解析。将String2DateConverter的BeanDefinitionHolder 转换为ManageList保存到ConversionServiceFactoryBean的BeanDefinition中。
  2. converters属性注入: 先通过getBeanInfo将ConversionServiceFactoryBean的所有的属性信息保存到cachedIntrospectionResults中
  3. 调用convertForProperty方法,获得CustomCollectionEditor转换器,将List集合转换成LinkedHashSet集合。
  4. 通过反射为converters赋值
  5. 根据User对象birth属性的Date类型,从converters中获取到String2DateConverter转换器。
  6. 调用String2DateConverter的convert方法,将String类型转换成Date类型。
  7. 调用BeanWrapperImpl的setPropertyValues方法将Date类型的值通过反射赋给User的birth属性。

到这里,终于完成了自定义转换器的解析,不过还是希望读者自行调试,才能理解Spring源码的精粹。

本文的github地址是
https://github.com/quyixiao/spring_tiny/tree/master/src/main/java/com/spring_101_200/test_111_120/test_114_conversion2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值