Spring读源码系列番外篇---06----类型转换---下---ConversionService相关家族

Posted 大忽悠爱忽悠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring读源码系列番外篇---06----类型转换---下---ConversionService相关家族相关的知识,希望对你有一定的参考价值。

Spring读源码系列番外篇---06----类型转换---下


系列文章:

Spring读源码系列番外篇—01–PropertyValue相关类

Spring读源码系列番外篇—02—PropertyResolver的结构体系剖析—上

Spring读源码系列番外篇—03—PropertyResolver的结构体系剖析—下

Spring读源码系列番外篇—04----类型转换–上

Spring读源码系列番外篇—05----类型转换—中


引子

Spirng 3.0全新一代的类型转换机制,它提供的三种类型转换器(Converter、ConverterFactory、GenericConverter),分别可处理1:1、1:N、N:N的类型转换。

按照Spring的设计习惯,必有一个注册中心来统一管理,负责它们的注册、删除等,它就是ConverterRegistry。

另外,内建的绝大多数转换器访问权限都是default/private,那么如何使用它们,以及屏蔽各种转换器的差异化呢?为此,Spring提供了一个统一类型转换服务,它就是ConversionService。


新一代类型转换组件简介

ConverterRegistry和ConversionService的关系密不可分,前者为后者提供转换器管理支撑,后者面向使用者提供服务。本文涉及到的接口/类有:

  • ConverterRegistry:转换器注册中心。负责转换器的注册、删除
  • ConversionService:统一的类型转换服务。属于面向开发者使用的门面接口
  • ConfigurableConversionService:上两个接口的组合接口
  • GenericConversionService:上个接口的实现,实现了注册管理、转换服务的几乎所有功能,是个实现类而非抽象类
  • DefaultConversionService:继承自GenericConversionService,在其基础上注册了一批默认转换器(Spring内建),从而具备基础转换能力,能解决日常绝大部分场景


ConverterRegistry

public interface ConverterRegistry 
    //注册一个1:1的转换器----会尝试去参数化类型中提取sourceType和targetType
	void addConverter(Converter<?, ?> converter);

 //注册一个1:1的转换器----明确sourceType和targetType
	<S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter);

  //注册一个n:n的转换器
	void addConverter(GenericConverter converter);

//注册一个1:n的转化器
	void addConverterFactory(ConverterFactory<?, ?> factory);

//移除某个转换器
	void removeConvertible(Class<?> sourceType, Class<?> targetType);



ConverterRegistry有子接口FormatterRegistry,它属于格式化器的范畴.


ConversionService

面向使用者的统一类型转换服务。换句话说:站在使用层面,你只需要知道ConversionService接口API的使用方式即可,并不需要关心其内部实现机制,可谓对使用者非常友好。

public interface ConversionService 
	
	boolean canConvert(Class<?> sourceType, Class<?> targetType);
	boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
	
	<T> T convert(Object source, Class<T> targetType);
	Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);



可以看到ConversionService和ConverterRegistry的继承树殊途同归,都直接指向了ConfigurableConversionService这个分支,下面就对它进行介绍


ConfigurableConversionService

ConversionService和ConverterRegistry的组合接口,自己并未新增任何接口方法。

public interface ConfigurableConversionService extends ConversionService, ConverterRegistry 



插眼: ResolvableType

为什么要先提一嘴这个类呢?

当然是因为我们下面要将的GenericConversionService源码中大量使用到了这个类

该类作用很简单,我这里简单介绍一下,就不贴出源码了,毕竟方法挺多的:

  • 封装一个JAVA类型,提供对父类,接口和反向的访问已经最终解析为class的能力
  • ResolvableTypes 可以从字段、方法参数、方法返回或类中获得。此类中的大多数方法本身都会返回 ResolvableTypes,从而可以轻松导航
   private HashMap<Integer, List<String>> myMap;
  
   public void example() 
       ResolvableType t = ResolvableType.forField(getClass().getDeclaredField("myMap"));
       t.getSuperType(); // AbstractMap<Integer, List<String>>
       t.asMap(); // Map<Integer, List<String>>
       t.getGeneric(0).resolve(); // Integer
       t.getGeneric(1).resolve(); // List
       t.getGeneric(1); // List<String>
       //第二个泛型,里面的泛型,即List<String>里面的String
       t.resolveGeneric(1, 0); // String
   

通过上面这个简单案例应该可以让各位有个大概的了解,这就差不多了,那么我们进入正题吧

我觉得这个类,有空可以参考在自己项目中用用,毕竟算是一个比较方便的工具类


GenericConversionService

对ConfigurableConversionService接口提供了完整实现的实现类。换句话说:ConversionService和ConverterRegistry接口的功能均通过此类得到了实现,所以它是本文重点。

public class GenericConversionService implements ConfigurableConversionService 

	/**
	 * General NO-OP converter used when conversion is not required.
	 * 
	 */
	private static final GenericConverter NO_OP_CONVERTER = new NoOpConverter("NO_OP");

	/**
	 * Used as a cache entry when no converter is available.
	 * This converter is never returned.
	 */
	private static final GenericConverter NO_MATCH = new NoOpConverter("NO_MATCH");

    
    //Converters是GenericConversionService的内部类,用于管理(添加、删除、查找)转换器们。
    //也就说对ConverterRegistry接口的实现最终是委托给它去完成的,它是整个转换服务正常work的内核
	private final Converters converters = new Converters();
    
    //它用两个成员变量来管理转换器们,其中converterCache是缓存用于加速查找,因此更为重要的便是Converters喽。 
	private final Map<ConverterCacheKey, GenericConverter> converterCache = new ConcurrentReferenceHashMap<>(64);


	//-------------------------ConverterRegistry注册相关接口的具体实现------------------------
   
    //增加一个1:1的转化器
	@Override
	public void addConverter(Converter<?, ?> converter) 
	//getRequiredTypeInfo是一个工具方法,功能是返回传入converter的具体的泛型参数数组
	//泛型参数都被ResolvableType进行包裹,长度为2,一个是原对象类型,一个是目标对象类型
		ResolvableType[] typeInfo = getRequiredTypeInfo(converter.getClass(), Converter.class);
		//对代理进行判断---这个地方我暂时不清楚,等后面我懂了,就回来完善一下!!!
		if (typeInfo == null && converter instanceof DecoratingProxy) 
           //这套组合拳目的在于拿到泛型参数数组
			typeInfo = getRequiredTypeInfo(((DecoratingProxy) converter).getDecoratedClass(), Converter.class);
		
		if (typeInfo == null) 
			throw new IllegalArgumentException("Unable to determine source type <S> and target type <T> for your " +
					"Converter [" + converter.getClass().getName() + "]; does the class parameterize those types?");
		
		//添加转换器----将所有converter都通过ConverterAdapter转换为
		addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1]));
	

//和上面那个重载方法相比,少了去解析出convert泛型参数的过程
	@Override
	public <S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter) 
	//这一步和上面那个重载方法一样---这里也用到了适配器模式和上面一样
		addConverter(new ConverterAdapter(
				converter, ResolvableType.forClass(sourceType), ResolvableType.forClass(targetType)));
	

//上面两个重载方法最终调用的方法--这里参数需要的是GenericConverter
//因为我们之前说过有1:1,1:n,n:n三种转换器,因此我们这边把所有转换器都转换为通用的GenericConverter(n:n)进行管理
	@Override
	public void addConverter(GenericConverter converter) 
	//converters是一个内部类,它管理所有转换器,包括添加、删除、查找。
	//这个一会在细聊
		this.converters.add(converter);
		//清除缓存集合
		invalidateCache();
	

//添加一个1:n的转换器
	@Override
	public void addConverterFactory(ConverterFactory<?, ?> factory) 
	   //同样因为转换器的泛型参数不确定,因此需要先解析出来
		ResolvableType[] typeInfo = getRequiredTypeInfo(factory.getClass(), ConverterFactory.class);
		//处理代理问题
		if (typeInfo == null && factory instanceof DecoratingProxy) 
			typeInfo = getRequiredTypeInfo(((DecoratingProxy) factory).getDecoratedClass(), ConverterFactory.class);
		
		if (typeInfo == null) 
			throw new IllegalArgumentException("Unable to determine source type <S> and target type <T> for your " +
					"ConverterFactory [" + factory.getClass().getName() + "]; does the class parameterize those types?");
		
		//ConverterFactoryAdapter是将ConverterFactory转换为通用的GenericAdapter
		addConverter(new ConverterFactoryAdapter(factory,
				new ConvertiblePair(typeInfo[0].toClass(), typeInfo[1].toClass())));
	

//移除某个转换器
	@Override
	public void removeConvertible(Class<?> sourceType, Class<?> targetType) 
	//可以看出是converters管理某个转换器的删除
		this.converters.remove(sourceType, targetType);
		//清空缓存
		invalidateCache();
	


	// ConversionService implementation

	@Override
	public boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType) 
		Assert.notNull(targetType, "Target type to convert to cannot be null");
		//将Class包装为TypeDescriptor,然后交给重载方法进行处理
		return canConvert((sourceType != null ? TypeDescriptor.valueOf(sourceType) : null),
				TypeDescriptor.valueOf(targetType));
	

	@Override
	public boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) 
		Assert.notNull(targetType, "Target type to convert to cannot be null");
		if (sourceType == null) 
			return true;
		
		//能否进行转换就是去找到有无可用的转换器
		//这里如果一开始缓存中没有,那么找到后会加入缓存中,这样一会进行转换的时候,就会直接从缓存中取
		//如果找不到也会放入缓存集合--相当于做个标记
		GenericConverter converter = getConverter(sourceType, targetType);
		return (converter != null);
	

	/**
      是否不需要进行任何类型转换
	 */
	public boolean canBypassConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) 
		Assert.notNull(targetType, "Target type to convert to cannot be null");
		if (sourceType == null) 
			return true;
		
		//如果不需要进行任何类型转换,那么getConverter会返回NO_OP_CONVERTER---表示当前类型对不需要进行转换
		GenericConverter converter = getConverter(sourceType, targetType);
		return (converter == NO_OP_CONVERTER);
	

	@Override
	@SuppressWarnings("unchecked")
	@Nullable
	//将source对象转换为targetType类型
	public <T> T convert(@Nullable Object source, Class<T> targetType) 
		Assert.notNull(targetType, "Target type to convert to cannot be null");
		//最终调用的是重载方法来进行处理
		return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));
	

	@Override
	@Nullable
	public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) 
		Assert.notNull(targetType, "Target type to convert to cannot be null");
		//如果原对象类型为null,那么对应的source对象肯定也为null
		if (sourceType == null) 
			Assert.isTrue(source == null, "Source must be [null] if source type == [null]");
			//convertNullSource:如果targetType是Optional类型,最终返回的是Optional.empty()
			//否则返回null
			//handleResult:返回第三个参数作为返回结果,如果第三个参数为null,会抛出异常
			return handleResult(null, targetType, convertNullSource(null, targetType));
		
		//sourceType必须是Source的类型--isInstance---》InstanceOf
		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) 
		    //ConversionUtils.invokeConverter最终就是调用converter的converter方法
			Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
			//主要对第三个参数是否为空进行校验
			return handleResult(sourceType, targetType, result);
		
		//source为null,直接返回null,或者target是source的父类,返回直接返回source即可,不需要进行任何类型转换操作
		return handleConverterNotFound(source, sourceType, targetType);
	

	@Nullable
	public Object convert(@Nullable Object source, TypeDescriptor targetType) 
		return convert(source, TypeDescriptor.forObject(source), targetType);
	

	@Override
	public String toString() 
		return this.converters.toString();
	


	// Protected template methods
    
	@Nullable
	protected Object convertNullSource(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) 
		//null--->Optional,那么最终转换后得到的是Optional.empty()
		if (targetType.getObjectType() == Optional.class) 
			return Optional.empty();
		
		return null;
	


	@Nullable
	protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) 
		//构建缓存key
		ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
		//先尝试从缓存中去获取
		GenericConverter converter = this.converterCache.get(key);
		if (converter != null) 
			//缓存中存在
			//这里提前说一下:如果某个类型对不存在与之关联的转换器,那么在第一次查找无果后
			//会在缓存中进行标记,即当前key--->NO_MATCH
			//因此如果这里存在转换器,但是为NO_MATCH ,表示不存在对应的转换器可以转换该类型对,返回null即可
			return (converter != NO_MATCH ? converter : null);
		
        //converters负责通过类型对去查找到指定的转换器
		converter = this.converters.find(sourceType, targetType);
		//如果找不到
		if (converter == null) 
		//如果source和target之间是父子关系,那么返回NO_OP_CONVERTER,表示不需要进行类型转换
		//否则返回null
			converter = getDefaultConverter(sourceType, targetType);
		
        //如果到这里找到了对应的转换器,那么会放入缓存中
		if (converter != null) 
			this.converterCache.put(key, converter);
			return converter;
		
        //走到这里,说明找不到,那么当前类型对会和一个NO_MATCH的转换器进行关联
		this.converterCache.put(key, NO_MATCH);
		return null;
	
	
			//如果source和target之间是父子关系,那么返回NO_OP_CONVERTER,表示不需要进行类型转换
		//否则返回null
	@Nullable
	protected GenericConverter getDefaultConverter(TypeDescriptor sourceType, TypeDescriptor targetType) 
		return (sourceType.isAssignableTo(targetType) ? NO_OP_CONVERTER : null);
	


	// ---------------------Internal helpers:内部帮助的方法 --

以上是关于Spring读源码系列番外篇---06----类型转换---下---ConversionService相关家族的主要内容,如果未能解决你的问题,请参考以下文章

Spring读源码系列番外篇---05----类型转换---中---三种全新的类型转换器

Spring读源码系列番外篇08---BeanWrapper没有那么简单--上

Spring读源码系列番外篇08---BeanWrapper没有那么简单--中

Spring读源码系列番外篇---03---PropertyResolver的结构体系剖析---下

Spring读源码系列番外篇---02---PropertyResolver的结构体系剖析---上

重学springboot系列番外篇之RestTemplate