Spring源码分析:类型转换(一)之PropertyEditor和ConversionService

摘要:
控制台最终打印Person类的相关属性。发现@Value中的配置内容将被解析为相应的字段。因为@Value中写的内容最初是String类型,为什么Integer、Date、String[]和File类型字段指定了将外部设置转换为内部JavaBean属性值的转换接口方法,并使用字符串更新属性的内部值;
引子

创建Person类:

@Data
@Component
public class Person {

	@Value("wj")
	private String name;

	@Value("20")
	private Integer age;

	@Value("2020/10/10 12:30:30")
	private Date birth;

	@Value("java,html")
	private String[] subject;

	@Value("C:\\SoftPlugin.dll")
	private File file;

	@Override
	public String toString() {
		return "Person{" +
				"name='" + name + '\'' +
				", age=" + age +
				", birth=" + birth +
				", subject=" + Arrays.toString(subject) +
				", file=" + file +
				'}';
	}
}

创建配置类:

@ComponentScan("com.wj.spring2")
@Configuration
public class MainConfig {
}

main方法:

	public static void main(String[] args){
		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
		Person bean = applicationContext.getBean(Person.class);
		System.out.println(bean);
	}

运行结果:

image-20211216170253053

控制台最后打印了Person类的相关属性,发现@Value中的配置的内容会被解析到对应的字段上,String类型的name被设置进去还说的通,因为@Value中写的内容本来就是String类型的,那么为什么Integer、Date、String[]、File类型的字段,只要符合一定的格式,就能被正确解析,Spring底层是怎么做的,用了什么组件?我怎么对类型转换进行扩展?

留着问题慢慢往下看!!!

Spring类型转换的几种方式

PropertyEditor

PropertyEditor:属性编辑器,java.beans包下面的,它规定了将外部设置值转换为内部JavaBean属性值的转换接口方法。PropertyEditor主要的接口方法说明如下:

  • Object getValue():返回属性的当前值。基本类型被封装成对应的包装类实例;
  • void setValue(Object newValue):设置属性的值,基本类型以包装类传入(自动装箱);
  • String getAsText():将属性对象用一个字符串表示,以便外部的属性编辑器能以可视化的方式显示。缺省返回null,表示该属性不能以字符串表示;
  • void setAsText(String text):用一个字符串去更新属性的内部值,这个字符串一般从外部属性编辑器传入;
  • String[] getTags():返回表示有效属性值的字符串数组(如boolean属性对应的有效Tag为true和false),以便属性编辑器能以下拉框的方式显示出来。缺省返回null,表示属性没有匹配的字符值有限集合;
  • String getJavaInitializationString():为属性提供一个表示初始值的字符串,属性编辑器以此值作为属性的默认值。
  • void addPropertyChangeListener(PropertyChangeListener listener):添加属性改变监听器
  • void removePropertyChangeListener(PropertyChangeListener listener): 移除属性改变监听器

Java为PropertyEditor提供了一个方便的实现类:PropertyEditorSupport,该类实现了PropertyEditor接口并提供默认实现,一般情况下,用户可以通过扩展这个方便类设计自己的属性编辑器。

下面我们简单实现一个属性编辑器,用于将String类型转换成Date类型:

public class DatePropertyEditor extends PropertyEditorSupport {

	private static final String[] parsePatterns = {"yyyy-MM-dd","yyyy年MM月dd日",
			"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy/MM/dd",
			"yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyyMMdd"};


	@Override
	public void setAsText(String text) throws IllegalArgumentException {
		try {
            //org.apache.commons.lang3.time.DateUtils
			Date date = DateUtils.parseDate(text, parsePatterns);
			setValue(date);
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}
}

测试:

	public static void main(String[] args) {
		PropertyEditor editor = new DatePropertyEditor();
		editor.setAsText("2021-10-10 12:00:01");
		System.out.println(editor.getValue());
	}

输出结果:

image-20211216173139191

现在我们如果将前面Person类中的Date值改掉:

	@Value("2020-10-10 12:30:30")
	private Date birth;

再运行就会报错:

image-20211216174122560

为什么会出现这种情况?这个我们稍后解释。

但是为了解决这种问题,spring给我们提供了一种增加自定义PropertyEditor的方式:在配置类中增加如下bean

	@Bean
	CustomEditorConfigurer customEditorConfigurer() {
		CustomEditorConfigurer configurer = new CustomEditorConfigurer();
		Map<Class<?>, Class<? extends PropertyEditor>> customEditorsMap = new HashMap<>();
                //表示DatePropertyEditor可以将String类型转换成Date类型
                //spring中,如果发现输入类型是String,输出类型是Date,那么就会使用该PropertyEditor
		customEditorsMap.put(Date.class, DatePropertyEditor.class);
		configurer.setCustomEditors(customEditorsMap);
		return configurer;
	}

再运行就运行成功了:

image-20211216174510034

这说明我们自定义的属性编辑器生效了,把字符串转换成Date类型。

但是,jdk提供的PropertyEditor有很大的局限性,只能将String类型转换成其他类型,但是对于Object转成Object类型就没有办法了,所以Spring提供了强大的类型转换服务ConversionService供我们使用。

三种转换器

image-20211217094318092

Converter<S, T> (1:1转换)

接口源码:

@FunctionalInterface
public interface Converter<S, T> {

    /**
    * 转换方法:将S类型转换成T
    */
	@Nullable
	T convert(S source);

    /**
    * 支持链式调用
    */
	default <U> Converter<S, U> andThen(Converter<? super T, ? extends U> after) {
		Assert.notNull(after, "After Converter must not be null");
		return (S s) -> {
			T initialResult = convert(s);
			return (initialResult != null ? after.convert(initialResult) : null);
		};
	}

}

Converter接口用于将S类型转换成T类型。

下面对它进行测试:我们可以用Spring提供的StringToBooleanConverter,可以将String转换成Boolean类型。

        ConversionService conversionService = new DefaultConversionService();
        Boolean flag = conversionService.convert("1", Boolean.class);
        System.out.println(flag);

测试结果:

image-20211217104853560

???不是说Converter吗,怎么用的是ConversionService

其实我们创建了一个DefaultConversionService,它内部创建了很多Converter的实现。然后我们调用conversionService.convert时,它内部去匹配Converter,然后调用Converterconvert方法,这个后面再说。

ConverterFactory<S, R> (1:N转换)

源码如下:

public interface ConverterFactory<S, R> {

    //R 的子类都可以统一由这个 ConverterFactory 进行转换。
	<T extends R> Converter<S, T> getConverter(Class<T> targetType);

}

测试:

		System.out.println(conversionService.convert(1.2, Long.class));
		System.out.println(conversionService.convert(1.2, Double.class));

image-20211217105729487

这里,conversionService底层使用了NumberToNumberConverterFactory类去转换:

final class NumberToNumberConverterFactory implements ConverterFactory<Number, Number>, ConditionalConverter {

	@Override
	public <T extends Number> Converter<Number, T> getConverter(Class<T> targetType) {
		return new NumberToNumber<>(targetType);
	}

	@Override
	public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
		return !sourceType.equals(targetType);
	}


	private static final class NumberToNumber<T extends Number> implements Converter<Number, T> {

		private final Class<T> targetType;

		NumberToNumber(Class<T> targetType) {
			this.targetType = targetType;
		}

		@Override
		public T convert(Number source) {
                        //NumberUtils.convertNumberToTargetClass方法去转换
			return NumberUtils.convertNumberToTargetClass(source, this.targetType);
		}
	}

}

GenericConverter (N:N转换)

GenericConverter一般都是和ConditionalConverter一起使用的。

源码如下:

public interface GenericConverter {

    //获取当前GenericConverter的source==>target的转换对
	@Nullable
	Set<ConvertiblePair> getConvertibleTypes();

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

	/**
	* 用于存储 sourc===>target 的转换对
	*/
	final class ConvertiblePair {

		private final Class<?> sourceType;

		private final Class<?> targetType;

		public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {
			Assert.notNull(sourceType, "Source type must not be null");
			Assert.notNull(targetType, "Target type must not be null");
			this.sourceType = sourceType;
			this.targetType = targetType;
		}
		//其他方法省略
	}
}

public interface ConditionalConverter {
	//判断当前converter能否从sourceType转换成targetType
	boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
//继承了GenericConverter和ConditionalConverter
public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {
}

测试:我们可以通过CollectionToCollectionConverter将List<String>转换成Set<Integer>:

        ConversionService conversionService = new DefaultConversionService();
        Set<Integer> set = (Set<Integer>)conversionService.convert(Arrays.asList("1","2","1"),
                TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)),
                TypeDescriptor.collection(Set.class, TypeDescriptor.valueOf(Integer.class)));
        System.out.println(set);

运行结果:

image-20211217120028090

CollectionToCollectionConverter源码说明:

final class CollectionToCollectionConverter implements ConditionalGenericConverter {

	private final ConversionService conversionService;


	public CollectionToCollectionConverter(ConversionService conversionService) {
		this.conversionService = conversionService;
	}


	@Override
	public Set<ConvertiblePair> getConvertibleTypes() {
		return Collections.singleton(new ConvertiblePair(Collection.class, Collection.class));
	}

	@Override
	public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
		return ConversionUtils.canConvertElements(
				sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), this.conversionService);
	}

	@Override
	@Nullable
	public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
                //如果要转换的source为null,则直接返回
		if (source == null) {
			return null;
		}
                //将source强转为Collection
		Collection<?> sourceCollection = (Collection<?>) source;

		// Shortcut if possible...
                //判断targetType集合类型与sourceType集合类型是否相同
		boolean copyRequired = !targetType.getType().isInstance(source);
		if (!copyRequired && sourceCollection.isEmpty()) {
                        //不用转换,直接返回
			return source;
		}
        
		TypeDescriptor elementDesc = targetType.getElementTypeDescriptor();
                //判断集合元素类型是否设置了,如果没有则为Object类型,且集合类型没有变
		if (elementDesc == null && !copyRequired) {
                        //不用转换,直接返回
			return source;
		}

		// At this point, we need a collection copy in any case, even if just for finding out about element copies...
                //创建原集合大小的空集合
		Collection<Object> target = CollectionFactory.createCollection(targetType.getType(),
				(elementDesc != null ? elementDesc.getType() : null), sourceCollection.size());
		//如果没有设置集合元素类型
		if (elementDesc == null) {
                        //直接addAll
			target.addAll(sourceCollection);
		}
		else {
                        //遍历原集合的所有元素,依次调用conversionService.convert()方法,将sourceElement转换成targetElement
                        //并将转换结果放到新集合中
			for (Object sourceElement : sourceCollection) {
				Object targetElement = this.conversionService.convert(sourceElement,
						sourceType.elementTypeDescriptor(sourceElement), elementDesc);
				target.add(targetElement);
				if (sourceElement != targetElement) {
					copyRequired = true;
				}
			}
		}

		return (copyRequired ? target : source);
	}

}

ConversionService

Spring 3.0 提供了三种类型的转换器(ConverterConverterFactoryGenericConverter),分别用来处理 1:1、1:N、N:N 的类型转换。而ConversionService是来统一管理所有的类型转换器,负责注册、查找、转换等功能,统一对外提供服务。

查看该类实现:

image-20211217140232244

ConversionService还有一个FormattingConversionService的实现,因为它跟Formatter有关,不再本文讨论之内,这里不再介绍。

  • ConverterRegistry:转换器注册中心。负责转换器的注册、删除

  • ConversionService:统一的类型转换服务。属于面向开发者使用的门面接口

  • ConfigurableConversionService:上两个接口的组合接口

  • GenericConversionService 实现了 ConfigurableConversionService 接口,Spring 使用的 ConversionService 都是基于这个类的扩展。

  • DefaultConversionService 扩展 GenericConversionService,注册了一批默认的转换器。

GenericConversionService

save

GenericConversionService 实现了 ConversionService, ConverterRegistry 两个接口的功能,上面提到的 DefaultConversionService 就是基于 GenericConversionService 的扩展,只是注册了一些默认的转换器。

接下来:先介绍GenericConversionService的增加转换器方法:

	//管理所有已经注册在ConversionService的Converter
	private final Converters converters = new Converters();

	@Override
	public void addConverter(Converter<?, ?> converter) {
		//获取传进来的Converter的两个泛型类型
		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转成Converter的适配器, 该ConverterAdapter实现ConditionalGenericConverter接口(支持N:N转换)
		addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1]));
	}

	//将明确指定source/target的类型对添加到ConverterRegistry
	//允许将 Converter 重用于多个不同的对,而无需为每对创建 Converter 类。
	@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)));
	}

	//增加ConverterFactory支持1:N
	@Override
	public void addConverterFactory(ConverterFactory<?, ?> factory) {
                //获取传进来的ConverterFactory的两个泛型类型
		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?");
		}
		//将ConverterFactory转成ConverterFactory适配器,该适配器实现ConditionalGenericConverter接口(支持N:N转换)
		addConverter(new ConverterFactoryAdapter(factory,
				new ConvertiblePair(typeInfo[0].toClass(), typeInfo[1].toClass())));
	}

	//增加GenericConverter
	@Override
	public void addConverter(GenericConverter converter) {
		this.converters.add(converter);
		invalidateCache();
	}

可以看到,当增加Converter或者是ConverterFactory,ConversionService都会先创建该转换器的适配器,实现了ConditionalGenericConverter接口,然后调用addConverter(GenericConverter converter)方法,确保无论是添加哪种转换器,最终在ConversionService中注册的都是GenericConverter,巧妙如斯!!

最终调用this.converters.add(converter);,converters是GenericConversionService类的属性,是Converters类:

	private static class Converters {

		private final Set<GenericConverter> globalConverters = new CopyOnWriteArraySet<>();

		private final Map<ConvertiblePair, ConvertersForPair> converters = new ConcurrentHashMap<>(256);

		public void add(GenericConverter converter) {
			//获取该converter的source/target类型对
			Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();
			if (convertibleTypes == null) {
				Assert.state(converter instanceof ConditionalConverter,
						"Only conditional converters may return null convertible types");
                                //如果类型对为null,添加到globalConverters的集合中
				this.globalConverters.add(converter);
			}
			else {
                                //遍历convertibleTypes
				for (ConvertiblePair convertiblePair : convertibleTypes) {
					//getMatchableConverters(convertiblePair)返回ConvertersForPair后,调用它的add方法,增加converter
					getMatchableConverters(convertiblePair).add(converter);
				}
			}
		}

		//从converters根据convertiblePair获取ConvertersForPair,如果没有就创建一个空的ConvertiblePair---ConvertersForPair键值对
		private ConvertersForPair getMatchableConverters(ConvertiblePair convertiblePair) {
			return this.converters.computeIfAbsent(convertiblePair, k -> new ConvertersForPair());
		}
        
        //其他方法省略。。

再看ConvertersForPair类:

	/**
	 * Manages converters registered with a specific {@link ConvertiblePair}.
	 */
	private static class ConvertersForPair {

                //真正存放GenericConverter的地方
		private final Deque<GenericConverter> converters = new ConcurrentLinkedDeque<>();

		//把converter放到队首,所以越后add的GenericConverter越在前面
		public void add(GenericConverter converter) {
			this.converters.addFirst(converter);
		}

		//其他方法省略
	}

所以最终存储结构是这样:(当然了,这只是简化版的,GenericConversionService实际上比这个还要复杂一点)

spring类型转换

remove

先看GenericConversionServiceremoveConvertible方法:

	@Override
	public void removeConvertible(Class<?> sourceType, Class<?> targetType) {
                //直接调用Converters的remove方法,移除转换类型对
		this.converters.remove(sourceType, targetType);
		invalidateCache();
	}

再看Convertersremove方法:直接调用原生的map的remove方法,从map中移除指定的ConvertiblePair key,这样也就会把该key对应的所有转换器对象移除。

		public void remove(Class<?> sourceType, Class<?> targetType) {
			this.converters.remove(new ConvertiblePair(sourceType, targetType));
		}

canConvert和convert

接下来,重头戏来了。我们先看GenericConversionServicecanConvert的实现:

	//canConvert(@Nullable Class<?> sourceType, Class<?> targetType)调用的是该类的同名重载方法
	@Override
	public boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType) {
		Assert.notNull(targetType, "Target type to convert to cannot be null");
		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");
                //如果sourceType等于null,直接返回true
		if (sourceType == null) {
			return true;
		}
                //调用getConverter方法,如果能得到converter,就返回true
		GenericConverter converter = getConverter(sourceType, targetType);
		return (converter != null);
	}

再看getConverter方法:

	private static final GenericConverter NO_MATCH = new NoOpConverter("NO_MATCH");	
	private static final GenericConverter NO_OP_CONVERTER = new NoOpConverter("NO_OP");

	@Nullable
	protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
                //创建了source/target类型对的缓存key,这一次getConverter的结果会被缓存起来,后面再次调用getConverter,直接返回结果,提升查询的速度
		ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
                //先从缓存中查询缓存key对应的GenericConverter
		GenericConverter converter = this.converterCache.get(key);
		if (converter != null) {
                        //不等于null,判断该Converter是否是NO_MATCH,如果是,返回null,否则直接返回converter
                        //这里处理就有点向redis的缓存穿透问题一样,为不存在的key也设置一个空对象
			return (converter != NO_MATCH ? converter : null);
		}
		//如果converter为null,说明缓存中没有,则是第一次查询,所以直接从Converters中查询
                //调用find方法
		converter = this.converters.find(sourceType, targetType);
		if (converter == null) {
                        //获取默认的Converter
			converter = getDefaultConverter(sourceType, targetType);
		}
		//不等于null
		if (converter != null) {
                        //缓存这次查询的结果,并返回
			this.converterCache.put(key, converter);
			return converter;
		}
		//缓存一个空的converter
		this.converterCache.put(key, NO_MATCH);
                //返回null
		return null;
	}

	//如果源类型可分配给目标类型,则返回 NO_OP 转换器。
	//否则返回 null,表示找不到合适的转换器。
	@Nullable
	protected GenericConverter getDefaultConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
		return (sourceType.isAssignableTo(targetType) ? NO_OP_CONVERTER : null);
	}

再看Convertersfind方法:

		@Nullable
		public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {
			// Search the full type hierarchy
                        //获取source类型的类层级和target类型的类层级
			List<Class<?>> sourceCandidates = getClassHierarchy(sourceType.getType());
			List<Class<?>> targetCandidates = getClassHierarchy(targetType.getType());
                        //双重for循环遍历
			for (Class<?> sourceCandidate : sourceCandidates) {
				for (Class<?> targetCandidate : targetCandidates) {
                                        //创建source类型/target类型一个convertiblePair
					ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);
                                        //调用getRegisteredConverter()查找GenericConverter
					GenericConverter converter = getRegisteredConverter(sourceType, targetType, convertiblePair);
					if (converter != null) {
                                                //如果找到了,直接返回converter
						return converter;
					}
				}
			}
                        //没有找到,返回null
			return null;
		}

这里的getClassHierarchy返回类型的类层级是什么意思?

Double类型为例,我来解释一下:

Double类的继承实现关系如下:

image-20211217155026367

那么Double调用此方法,会返回它自己、它的父类和它的父接口:

最终返回[Class<Double>, Class<Number>, Class<Comparable>, Class<Serialzable>, Class<Object>],不要忘记Object类型,它也是Double的父类。

getClassHierarchy说完了,那么这里的双重循环是怎么回事?

无论source类型还是taget类型都有类层级,他会每两个一对依次去查。

以Double和Integer为例,查询顺序为:Double<==>Integer 到 Double<==>Number 到 Double<==>Comparable ... Number<==>Integer 到 Number<==>Number ...

以此类推,直至找到对应的类型转换器。

再看ConvertersgetRegisteredConverter方法,看它是怎么找到已经注册的Converter:

		//从此方法来看:converters的优先级要比globalConverters高
		@Nullable
		private GenericConverter getRegisteredConverter(TypeDescriptor sourceType,
				TypeDescriptor targetType, ConvertiblePair convertiblePair) {

			// Check specifically registered converters
			//直接从map中调用get(convertiblePair),找到convertersForPair
			ConvertersForPair convertersForPair = this.converters.get(convertiblePair);
			if (convertersForPair != null) {
				//从convertersForPair中找到Converter
				GenericConverter converter = convertersForPair.getConverter(sourceType, targetType);
				if (converter != null) {
					//找到,直接返回
					return converter;
				}
			}
			// Check ConditionalConverters for a dynamic match
			//如果converters的Map集合中找不到,就从globalConverters中找
			for (GenericConverter globalConverter : this.globalConverters) {
				//依次调用matches方法
				if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) {
					//找到就直接返回
					return globalConverter;
				}
			}
			//找不到返回null
			return null;
		}

再看ConvertersForPairgetConverter方法:

	private static class ConvertersForPair {

		private final Deque<GenericConverter> converters = new ConcurrentLinkedDeque<>();

		@Nullable
		public GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
			//遍历队列
			for (GenericConverter converter : this.converters) {
				//如果converter实现了ConditionalGenericConverter接口们则会调用matches方法,看是否匹配
				//如果没有实现,则直接返回
				if (!(converter instanceof ConditionalGenericConverter) ||
						((ConditionalGenericConverter) converter).matches(sourceType, targetType)) {
					return converter;
				}
			}
			return null;
		}
        //其他方法省略
	}

至此GenericConversionServicegetConverter方法调用结束。

getConverter流程图如下:图有点乱,毕竟判断比较多,最好还是自己断点走一遍。

GenericConversionService流程

canConvert看完后,再看convert方法:

	@Override
	@Nullable
	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() + "]");
		}
                //调用getConvert方法,与上面分析的getConverter方法是同一个方法
		GenericConverter converter = getConverter(sourceType, targetType);
		if (converter != null) {
                        //调用ConversionUtils的invokeConverter方法
			Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
                        //handleResult:处理返回值
			return handleResult(sourceType, targetType, result);
		 }
                //调用handleConverterNotFound方法
		return handleConverterNotFound(source, sourceType, targetType);
	}

先看invokeConverter方法:方法很简单,就是直接调用找到的GenericConverterconvert方法进行类型转换。

	@Nullable
	public static Object invokeConverter(GenericConverter converter, @Nullable Object source,
			TypeDescriptor sourceType, TypeDescriptor targetType) {

		try {
			return converter.convert(source, sourceType, targetType);
		}
		catch (ConversionFailedException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new ConversionFailedException(sourceType, targetType, source, ex);
		}
	}

handleResult方法也容易,就是判断result==null时,看targetType是否是原始类型,如果是,直接抛出异常

	@Nullable
	private Object handleResult(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType, @Nullable Object result) {
		if (result == null) {
			assertNotPrimitiveTargetType(sourceType, targetType);
		}
                //返回最终结果
		return result;
	}

再看handleConverterNotFound方法:

	@Nullable
	private Object handleConverterNotFound(
			@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {

		if (source == null) {
			//判断targetType是否是原始类型
			assertNotPrimitiveTargetType(sourceType, targetType);
			return null;
		}
		//当source类型为null或source类型可分配给target类型并且判断给定的source是否是target类型的实例
		//如果判断返回true,则直接返回source
		if ((sourceType == null || sourceType.isAssignableTo(targetType)) &&
				targetType.getObjectType().isInstance(source)) {
			return source;
		}
		//抛出异常
		throw new ConverterNotFoundException(sourceType, targetType);
	}

至此,GenericConversionService类基本分析完毕。

DefaultConversionService

接下来看GenericConversionService类的子类DefaultConversionService

//默认的类型转换服务
public class DefaultConversionService extends GenericConversionService {

	@Nullable
	private static volatile DefaultConversionService sharedInstance;

	//构造方法
	public DefaultConversionService() {
		addDefaultConverters(this);
	}

	//返回一个共享实例,此外使用双重检查锁保证了sharedInstance实例只会被创建一次
	public static ConversionService getSharedInstance() {
		DefaultConversionService cs = sharedInstance;
		if (cs == null) {
			synchronized (DefaultConversionService.class) {
				cs = sharedInstance;
				if (cs == null) {
                                        //调用构造方法
					cs = new DefaultConversionService();
					sharedInstance = cs;
				}
			}
		}
		return cs;
	}

	//增加一些默认的转换器
	public static void addDefaultConverters(ConverterRegistry converterRegistry) {
		addScalarConverters(converterRegistry);
		addCollectionConverters(converterRegistry);

		converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));
		converterRegistry.addConverter(new StringToTimeZoneConverter());
		converterRegistry.addConverter(new ZoneIdToTimeZoneConverter());
		converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter());

		converterRegistry.addConverter(new ObjectToObjectConverter());
		converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));
		converterRegistry.addConverter(new FallbackObjectToStringConverter());
		converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));
	}

	public static void addCollectionConverters(ConverterRegistry converterRegistry) {
		ConversionService conversionService = (ConversionService) converterRegistry;

		converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));
		converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));

		converterRegistry.addConverter(new ArrayToArrayConverter(conversionService));
		converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService));
		converterRegistry.addConverter(new MapToMapConverter(conversionService));

		converterRegistry.addConverter(new ArrayToStringConverter(conversionService));
		converterRegistry.addConverter(new StringToArrayConverter(conversionService));

		converterRegistry.addConverter(new ArrayToObjectConverter(conversionService));
		converterRegistry.addConverter(new ObjectToArrayConverter(conversionService));

		converterRegistry.addConverter(new CollectionToStringConverter(conversionService));
		converterRegistry.addConverter(new StringToCollectionConverter(conversionService));

		converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));
		converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));

		converterRegistry.addConverter(new StreamConverter(conversionService));
	}

	private static void addScalarConverters(ConverterRegistry converterRegistry) {
		converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());

		converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
		converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());

		converterRegistry.addConverter(new StringToCharacterConverter());
		converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());

		converterRegistry.addConverter(new NumberToCharacterConverter());
		converterRegistry.addConverterFactory(new CharacterToNumberFactory());

		converterRegistry.addConverter(new StringToBooleanConverter());
		converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());

		converterRegistry.addConverterFactory(new StringToEnumConverterFactory());
		converterRegistry.addConverter(new EnumToStringConverter((ConversionService) converterRegistry));

		converterRegistry.addConverterFactory(new IntegerToEnumConverterFactory());
		converterRegistry.addConverter(new EnumToIntegerConverter((ConversionService) converterRegistry));

		converterRegistry.addConverter(new StringToLocaleConverter());
		converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());

		converterRegistry.addConverter(new StringToCharsetConverter());
		converterRegistry.addConverter(Charset.class, String.class, new ObjectToStringConverter());

		converterRegistry.addConverter(new StringToCurrencyConverter());
		converterRegistry.addConverter(Currency.class, String.class, new ObjectToStringConverter());

		converterRegistry.addConverter(new StringToPropertiesConverter());
		converterRegistry.addConverter(new PropertiesToStringConverter());

		converterRegistry.addConverter(new StringToUUIDConverter());
		converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter());
	}

}

可以看到,当我们new出一个DefaultConversionService实例时,它内部会注册很多的不同功能的Converter

Spring中注册自定义类型转换器

关于类型转换服务,在refresh容器刷新方法的finishBeanFactoryInitialization这一步中:

	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		//初始化ConversionService
		//默认情况下是没有ConversionService的
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

刚开始,就会判断是否有conversionServicebean名称的ConversionService.class,如果有,就创建ConversionService的实例,并设置到beanFactory中。

所以如果我们想要在spring中使用ConversionService,只需要注册到spring容器中就行了。

此外Spring提供了一个ConversionServiceFactoryBeanFactoryBean,这样会方便我们的使用:

public class ConversionServiceFactoryBean implements FactoryBean<ConversionService>, InitializingBean {

	@Nullable
	private Set<?> converters;

	@Nullable
	private GenericConversionService conversionService;

	//此方法用于我们传入自定义的类型转换器
	public void setConverters(Set<?> converters) {
		this.converters = converters;
	}

	@Override
	public void afterPropertiesSet() {
                //调用createConversionService方法
		this.conversionService = createConversionService();
                //把converters注册到conversionService中
		ConversionServiceFactory.registerConverters(this.converters, this.conversionService);
	}

	//创建一个DefaultConversionService的实例
	protected GenericConversionService createConversionService() {
		return new DefaultConversionService();
	}

	@Override
	@Nullable
	public ConversionService getObject() {
		return this.conversionService;
	}

	@Override
	public Class<? extends ConversionService> getObjectType() {
		return GenericConversionService.class;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}

}

下面提供一个配置的示例:

@ComponentScan("com.wj.spring2")
@Configuration
public class MainConfig {

//	@Bean
//	CustomEditorConfigurer customEditorConfigurer() {
//		CustomEditorConfigurer configurer = new CustomEditorConfigurer();
//		Map<Class<?>, Class<? extends PropertyEditor>> customEditorsMap = new HashMap<>();
//		customEditorsMap.put(Date.class, DatePropertyEditor.class);
//		configurer.setCustomEditors(customEditorsMap);
//		return configurer;
//	}

    //注意这里方法名必须是conversionService,因为spring里面规定了,不然不会使用这个conversionService
    //此外我们自定义的类型转换器会优先与DefaultConversionService中默认的类型转换器
	//前面解释过了,底层维护的是一个队列,并且调用的addFirst方法
	@Bean
	ConversionServiceFactoryBean conversionService() {
		ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
		Set<Converter<?, ?>> set =  new HashSet<>();
		set.add(new StringToDateConverter());
		conversionServiceFactoryBean.setConverters(set);
		return conversionServiceFactoryBean;
	}

	private static class StringToDateConverter implements Converter<String, Date>{

		private final java.lang.String[] parsePatterns = {"yyyy-MM-dd","yyyy年MM月dd日",
				"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy/MM/dd",
				"yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyyMMdd"};

		@Override
		public Date convert(String source) {
			try {
				return DateUtils.parseDate(source, parsePatterns);
			} catch (ParseException e) {
				e.printStackTrace();
			}
			return null;
		}
	}
}

此外,spring还有一种类型转换方式:TypeConverter,将会于下一篇介绍。

免责声明:文章转载自《Spring源码分析:类型转换(一)之PropertyEditor和ConversionService》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Oracle 的几种循环方式介绍Python中Scapy网络嗅探模块的使用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

JNI数据类型(转)

  本文原创,转载请注明出处:http://blog.csdn.net/qinjuning     在Java存在两种数据类型: 基本类型 和 引用类型 ,大家都懂的 。     在JNI的世界里也存在类似的数据类型,与Java比较起来,其范围更具严格性,如下:         1、primitive types ----基本数据类型,如:int、 flo...

复制一个datatable的指定行到另外一个datatable dodo

DataTable dt = oldDataTable;DataTable result = dt.Clone();//复制表的结构            resultTable.Rows.Add(dt.Rows[index].ItemArray);//ItemArray ----通过一个数组来获取或设置此行的所有值 //新建表   DataTable ...

jQuery打印Html页面自动分页

最近项目中需要用到打印HTML页面,需要指定区域打印,使用jquery.PrintArea.js 插件 用法:  Javascript代码   $("div#printmain").printArea();   但还是会打印DIV后面的内容,这里可以使用CSS控制打印分页  Css代码   <div style="page-break-a...

关于DataGridView的索引

最近在做一个课堂练习是被郁闷了一把。现成的事成了想当然的事。案例如下。 是一个WinForm程序,在DataGridView绑定控件后,选择一行,进行操作,代码如下: 数据绑定代码: SqlDataAdapter da = newSqlDataAdapter("select id from shuji","server=.;database=tushudb...

Unity你用过哪些设计模式?你熟悉的设计模式有哪几种呢?

以前写过几篇设计模式的详细解释,今天在这里不详细介绍,有兴趣了解的可以去看前几篇随笔,今天就简单的介绍我们常用的设计模式. (1)工厂模式 简单工厂模式解决的问题是如何去实例化一个合适的对象. 简单工厂模式的核心思想就是:有一个专门的类来负责实例过程,范式出现大量产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建,比如说写技能是一系列类,那么...

Disruptor 详解

想了解一个项目,最好的办法就是,把它的源码搞到本地自己捣鼓。   在网上看了 N 多人对 Disruptor 速度的吹捧,M 多人对它的机制分析,就连 Disruptor 官方文档中,也 NB 哄哄自诩: At LMAX we have built an order matching engine, real-time risk management, a...