spring学习(六)——4 Spring的 类型转换

参考文章:

http://www.iocoder.cn/

 

在 Spring 容器加载阶段,容器将 xml 文件中定义的 <bean> 解析为 BeanDefinition,BeanDefinition 中存储着我们定义一个 bean 需要的所有信息,包括属性,这些属性是以 String 类型的存储的。当用户触发 Bean 实例化阶段时,Spring 容器会将这些属性转换为这些属性真正对应的类型。

执行类型转换的主要方法在AbstractAutowireCapableBeanFactory 的populateBean -> applyPropertyValues;

	@Override
	public void autowireBean(Object existingBean) {
		// Use non-singleton bean definition, to avoid registering bean as dependent bean.
          ………………
		// 进行属性转换
		populateBean(bd.getBeanClass().getName(), bd, bw);
	}
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        ………………

		if (pvs != null) {
			// 申请参数  pvs  PropertyValues
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

在applyPropertyValues中通过convertForProperty进行类型转换

	protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        ………………

		// 获得用户自定义的类型转换器
		TypeConverter converter = getCustomTypeConverter();
		if (converter == null) {
			converter = bw;
		}
		………………


		// Create a deep copy, resolving any references for values.
		// 做一次深拷贝
		List<PropertyValue> deepCopy = new ArrayList<>(original.size());
		boolean resolveNecessary = false;
		for (PropertyValue pv : original) {
			if (pv.isConverted()) {
				// 深拷贝
				deepCopy.add(pv);
			}
			else {
				………………

				if (convertible) {
					// 转换属性
					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.
				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));
				}
			}
		}
        …………

		// Set our (possibly massaged) deep copy.
		try {
			// 将 值转换为PropertyValue然后放入bean的包装类中
			bw.setPropertyValues(new MutablePropertyValues(deepCopy));
		}
		catch (BeansException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Error setting property values", ex);
		}
	}

convertForProperty

private Object convertForProperty(
			@Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
		// 若 TypeConverter 为 BeanWrapperImpl 类型,则使用 BeanWrapperImpl 来进行类型转换
		// 这里主要是因为 BeanWrapperImpl 实现了 PropertyEditorRegistry 接口
		if (converter instanceof BeanWrapperImpl) {
			return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
		}
		else {
			// 获得属性对应的 PropertyDescriptor 对象
			PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
			// 获得属性对应的 setting MethodParameter 对象
			MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
			// 进行转换
			return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
		}
	}

convertForProperty的主要内容是优先获得属性的描述对象,然后获得方法的描述对象,使用转换器,进行数据转换。

converter.convertIfNecessary主要有两个实现方法DataBinder 和 TypeConverterSupport

convertIfNecessary

public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable MethodParameter methodParam)
			throws TypeMismatchException {
		// 主要的执行转换的方法
		return doConvert(value, requiredType, methodParam, null);
	}
	private <T> T doConvert(@Nullable Object value,@Nullable Class<T> requiredType,
			@Nullable MethodParameter methodParam, @Nullable Field field) throws TypeMismatchException {

		Assert.state(this.typeConverterDelegate != null, "No TypeConverterDelegate");
		try {
			// 使用字段转换
			if (field != null) {
				return this.typeConverterDelegate.convertIfNecessary(value, requiredType, field);
			}
			else {
				// 使用方法参数集合进行转换
				return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
			}
		}
		catch (ConverterNotFoundException | IllegalStateException ex) {
			throw new ConversionNotSupportedException(value, requiredType, ex);
		}
		catch (ConversionException | IllegalArgumentException ex) {
			throw new TypeMismatchException(value, requiredType, ex);
		}
	}

最终追踪下我们发现真正进行类型转换使用的是TypeConverterDelegate的convertIfNecessary

	public <T> T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue,
			@Nullable Class<T> requiredType, @Nullable 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 conversionService = this.propertyEditorRegistry.getConversionService();
		if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
			// 获得newValue的类型描述符
			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;
				}
			}
		}

		……………………



		return (T) convertedValue;
	}

ConversionService 

目前转换器的主要处理逻辑在此接口下,此接口的关系图

其接口的代码逻辑为

public interface ConversionService {

	/**
	 * 是否可以以进行转换
	 * Return {@code true} if objects of {@code sourceType} can be converted to the {@code targetType}.
	 */
	boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);

	/**
	 */
	boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);

	/**
	 * 执行换换
	 */
	@Nullable
	<T> T convert(@Nullable Object source, Class<T> targetType);

	@Nullable
	Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);

}

其进行数据转换的主要代码逻辑为

	public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
		Assert.notNull(targetType, "Target type to convert to cannot be null");
		// 如果源数据类型为空,则可以直接处理
		if (sourceType == null) {
			Assert.isTrue(source == null, "Source must be [null] if source type == [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);
	}

进行转换主要三个方法,我们先分析这三个方法

  • getConverter
  • handleResult
  • handleConverterNotFound

getConverter 获得转换器

protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
    // 创建 ConverterCacheKey 对象
    ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
    // 从 converterCache 缓存中,获得 GenericConverter 对象 converter
    GenericConverter converter = this.converterCache.get(key);
    // 如果获得到,则返回 converter
    if (converter != null) {
        return (converter != NO_MATCH ? converter : null);
    }

    // 如果获取不到,则从 converters 中查找
    converter = this.converters.find(sourceType, targetType);
    // 如果查找不到,则获得默认的 Converter 对象
    if (converter == null) {
        converter = getDefaultConverter(sourceType, targetType);
    }

    // 如果找到 converter ,则添加 converter 到 converterCache 中,并返回 converter
    if (converter != null) {
        this.converterCache.put(key, converter);
        return converter;
    }

    // 如果找不到 converter ,则添加 NO_MATCH 占位符到 converterCache 中,并返回 null
    this.converterCache.put(key, NO_MATCH);
    return null;
}
ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);

spring底层重写了ConverterCacheKey的equals方法,这样使得,相同参数的的转换器key是一致的。

底层其实是spring从缓存中获得转换器,如果没有获取就去创建一个符合要求的转换器。而从其实现类可以发现,spring已经实现了相当多的类型转换。

 

 

handleResult

	private Object handleResult(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType, @Nullable Object result) {
		if (result == null) {
			assertNotPrimitiveTargetType(sourceType, targetType);
		}
		return result;
	}

做了一个简单的验证,验证值是否符合预期

handleConverterNotFound

	private Object handleConverterNotFound(
			@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
		// 情况一,如果 source 为空,则返回空
		if (source == null) {
			assertNotPrimitiveTargetType(sourceType, targetType);
			return null;
		}
		// 情况二,如果 sourceType 为空,或者 targetType 是 sourceType 的子类,则返回 source
		if ((sourceType == null || sourceType.isAssignableTo(targetType)) &&
				targetType.getObjectType().isInstance(source)) {
			return source;
		}
		// 抛出 ConverterNotFoundException 异常
		throw new ConverterNotFoundException(sourceType, targetType);
	}

判断返回null或者异常

 

实际上,大体的调用流是如下:TypeConverterSupport => ConversionService => Converter,具体想看spring

类型转换的具体实现以及缓存方式可以查看Converter的接口以及getConverter的方法。

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大·风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值