In-depth interpretation of the converter of spring-core in chapter 2

foreword

This chapter in-depth explains the use and details of spring's converter to help you use the converter correctly in your project. Converters are more practical and convenient functions in project development, but in complex business, architects or architecture teams are required to design and implement a complete set of specifications. Source code interpretation cannot be explained and interpreted in great detail through text. It requires readers to read many times, deeply understand, organize logic, and the brain slowly forms the whole process.

converter class relationship system

Enter image description

From the class instance diagram, it can be observed that the entire converter class relationship system is divided into two major blocks.

  • operating system
  • management system

operating system

Converter
public interface Converter<S, T> {
	T convert(S source);
}
ConverterFactory
public interface ConverterFactory<S, R> {
	<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}

Two very simple classes, the subclass of Converter is responsible for implementing the conversion, and what the ConverterFactory is used for. For example, there is a requirement to convert a number type into a string type, but there are more than ten subclasses of Number, such as Byte, Short, Integer, Long, etc., each of which has a Converter implementation (each must have a Converter, otherwise the code is very It is not easy to manage, and it is very inelegant to implement through methods), how to manage so many. Spring provides a solution to manage all Converters through the factory pattern using ConverterFactory

GenericConverter
public interface GenericConverter {

	Set<ConvertiblePair> getConvertibleTypes();

	Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
ConditionalConverter
public interface ConditionalConverter {
	boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {

}

Let everyone know in advance

  • The management system directly calls the subclass of GenericConverter, and then the subclass of GenericConverter performs conversion, such as direct conversion, or by calling the methods of Converter and ConverterFactory.
  • Every time the GenericConverter is obtained, the matches of the ConditionalConverter will be called to judge whether the condition is met, and the current object will be obtained when the condition is met. This is a very strange and very difficult to understand design. But the most important purpose of this design is to unify the behavior of Converter and ConverterFactory and keep them consistent. If you keep it consistent, please see the GenericConverter implementation classes ConverterFactoryAdapter and ConverterAdapter. There is also this design to ensure scalability.

management system

Enter image description

ConverterRegistry
public interface ConverterRegistry {

	void addConverter(Converter<?, ?> converter);

	void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter);

	void addConverter(GenericConverter converter);

	void addConverterFactory(ConverterFactory<?, ?> converterFactory);

	void removeConvertible(Class<?> sourceType, Class<?> targetType);

}

From the declared method, it can be seen that ConverterRegistry is responsible for the addition and deletion of converters

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

}

The declared method shows that ConversionService is responsible for converter execution and whether there is a corresponding type of converter

ConfigurableConversionService
public interface ConfigurableConversionService extends ConversionService, ConverterRegistry {

}

Well, ConfigurableConversionService is for viewing. It is mainly used to unify the interface of ConversionService and ConverterRegistry to facilitate the operation of classes.

GenericConversionService
public class GenericConversionService implements ConfigurableConversionService {
}

From the class declaration, we can know that GenericConversionService implements all methods of ConversionService and ConverterRegistry

First look at the non-inheritance and implementation methods of GenericConversionService
/**
   *如果目标类型是Optional,那么返回一个空Optional
**/
protected Object convertNullSource(TypeDescriptor sourceType, TypeDescriptor targetType) {
	if (javaUtilOptionalEmpty != null && targetType.getObjectType() == javaUtilOptionalEmpty.getClass()) {
		return javaUtilOptionalEmpty;
	}
	return null;
}


protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
   // 创建 ConverterCacheKey 对象,作为map的key,从converterCache得到converter对象
	ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
	GenericConverter converter = this.converterCache.get(key);
	// 从缓存中得到的converter是否为null
	if (converter != null) {
		return (converter != NO_MATCH ? converter : null);
	}
   // 从converters 查询converter
	converter = this.converters.find(sourceType, targetType);
	// 查询结果为空
	if (converter == null) {
		// 得到默认的 Converter
		converter = getDefaultConverter(sourceType, targetType);
	}
	//如果不等于空 把converter 加入缓存中
	if (converter != null) {
		this.converterCache.put(key, converter);
		return converter;
	}
	// 如果等于空,对应的操作的value是NO_MATCH
	this.converterCache.put(key, NO_MATCH);
	return null;
}

/**
 *  大家十分会很奇怪,已经有多个默认Converter的,为什么不值直接this.converterCache.put(key, NO_MATCH),
 *  还通过getDefaultConverter方法在得到一个默认的Converter。
 * GenericConversionService的getDefaultConverter会返回一个默认的NO_OP_CONVERTER,
 * GenericConversionService的子类可以通过重写getDefaultConverter方法得到子类想提供的DefaultConverter,
 * getDefaultConverter的存在提供了灵活的扩展
**/
protected GenericConverter getDefaultConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
	// sourceType.isAssignableTo(targetType) 用于判断类型与泛型都一致,如果一致就返回NO_OP_CONVERTER
	// NO_OP_CONVERTER的convert方法会直接方法传递的原数据(PS,点)
	return (sourceType.isAssignableTo(targetType) ? NO_OP_CONVERTER : null);
}


/**
 * 得到converter实参的泛型,
 * ConverterFactory<S, R> 与 Converter<S, T> 第一个泛型(S)是原类型,第二个泛型(R与T)是目标类型
**/
private ResolvableType[] getRequiredTypeInfo(Object converter, Class<?> genericIfc) {
	ResolvableType resolvableType = ResolvableType.forClass(converter.getClass()).as(genericIfc);
	ResolvableType[] generics = resolvableType.getGenerics();
	if (generics.length < 2) {
		return null;
	}
	Class<?> sourceType = generics[0].resolve();
	Class<?> targetType = generics[1].resolve();
	if (sourceType == null || targetType == null) {
		return null;
	}
	return generics;
}

private void invalidateCache() {
	this.converterCache.clear();
}

private Object handleConverterNotFound(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
	if (source == null) {
		assertNotPrimitiveTargetType(sourceType, targetType);
		return null;
	}
	// 如果目标类型与原类型一致,就直接方法原数据
	if (sourceType.isAssignableTo(targetType) && targetType.getObjectType().isInstance(source)) {
		return source;
	}
	throw new ConverterNotFoundException(sourceType, targetType);
}

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

private void assertNotPrimitiveTargetType(TypeDescriptor sourceType, TypeDescriptor targetType) {
	if (targetType.isPrimitive()) {// 目标类型是基本类型或者包装类型,就抛出异常。原因未知
		throw new ConversionFailedException(sourceType, targetType, null,
				new IllegalArgumentException("A null value cannot be assigned to a primitive type"));
	}
}
ConversionService implementation
@Override
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
	Assert.notNull(targetType, "targetType to convert to cannot be null");
	return canConvert((sourceType != null ? TypeDescriptor.valueOf(sourceType) : null),
			TypeDescriptor.valueOf(targetType));
}

@Override
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
	Assert.notNull(targetType, "targetType to convert to cannot be null");
	if (sourceType == null) {
		return true;
	}
	GenericConverter converter = getConverter(sourceType, targetType);
	return (converter != null);
}
// 用来识别,原类型与目标类型的converter是否是NO_OP_CONVERTER
public boolean canBypassConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
	Assert.notNull(targetType, "targetType to convert to cannot be null");
	if (sourceType == null) {
		return true;
	}
	GenericConverter converter = getConverter(sourceType, targetType);
	return (converter == NO_OP_CONVERTER);
}

@Override
@SuppressWarnings("unchecked")
public <T> T convert(Object source, Class<T> targetType) {
	Assert.notNull(targetType, "targetType to convert to cannot be null");
	return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));
}

@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) {
		// 执行converter 
		// converter.converter(source, sourceType, targetType); 封装了下代码,里面处理了异常
		// 异常,是返回null
		// converter.converter(source, sourceType, targetType) 结果也可能是也null,
		Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
		return handleResult(sourceType, targetType, result);
	}
	return handleConverterNotFound(source, sourceType, targetType);
}

public Object convert(Object source, TypeDescriptor targetType) {
	return convert(source, TypeDescriptor.forObject(source), targetType);
}

All methods can be analyzed from implementation

  • The first step is to get the original type and target type,
  • The second step calls the getConverter method,
  • The logic of the third step processing
Notice
  1. NO_OP_CONVERTER is a different instance of NO_MATCH, but the behavior is the same. convert returns the original data directly
public class GenericConversionService implements ConfigurableConversionService {

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

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

	private static class NoOpConverter implements GenericConverter {

	private final String name;

	public NoOpConverter(String name) {
		this.name = name;
	}

	@Override
	public Set<ConvertiblePair> getConvertibleTypes() {
		return null;
	}

	@Override
	public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
		return source;
	}

	@Override
	public String toString() {
		return this.name;
	}
	}
}
ConverterRegistry implementation content
@Override
public void addConverter(Converter<?, ?> converter) {
	ResolvableType[] typeInfo = getRequiredTypeInfo(converter, Converter.class);
	Assert.notNull(typeInfo, "Unable to the determine sourceType <S> and targetType " +
		"<T> which your Converter<S, T> converts between; declare these generic types.");
	addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1]));
	}

@Override
public void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter) {
	addConverter(new ConverterAdapter(converter,ResolvableType.forClass(sourceType), ResolvableType.forClass(targetType)));
}

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

@Override
public void addConverterFactory(ConverterFactory<?, ?> converterFactory) {
	ResolvableType[] typeInfo = getRequiredTypeInfo(converterFactory, ConverterFactory.class);
	Assert.notNull(typeInfo, "Unable to the determine source type <S> and target range type R which your " +
		"ConverterFactory<S, R> converts between; declare these generic types.");
	addConverter(new ConverterFactoryAdapter(converterFactory,new ConvertiblePair(typeInfo[0].resolve(), typeInfo[1].resolve())));
}

@Override
public void removeConvertible(Class<?> sourceType, Class<?> targetType) {
	this.converters.remove(sourceType, targetType);
	invalidateCache();
}

ConverterRegistry implementation content is very simple

  • The first step is to get the original type and target type,
  • The second step encapsulates the object converter with the original type and the target type into different sub-interfaces of the corresponding GenericConverter
  • The third step is to join converters
  • Part 4: Clear the cache
DefaultConversionService

DefaultConversionService registers many common Converters, and these common ConversionServices are very easy to use in ConversionService. In order to make the blog more readable, the source code is not posted here. You can go and see if you want.

converters core subsystem

ConvertiblePairs

ConvertiblePair is a simple entity class that overrides hashCode, equals, toString methods as the key of a Converters.converters

final class ConvertiblePair {

	private final Class<?> sourceType;

	private final Class<?> targetType;
}
ConvertersForPair
private static class ConvertersForPair {

	private final LinkedList<GenericConverter> converters = new LinkedList<GenericConverter>();

	public void add(GenericConverter converter) {
		this.converters.addFirst(converter);
	}

	public GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
		for (GenericConverter converter : this.converters) {
			if (!(converter instanceof ConditionalGenericConverter) ||
					((ConditionalGenericConverter) converter).matches(sourceType, targetType)) {
				return converter;
			}
		}
		return null;
	}

	@Override
	public String toString() {
		return StringUtils.collectionToCommaDelimitedString(this.converters);
	}
}

ConvertersForPair is a rather difficult class to understand. What does ConvertersForPair exist for?

ConvertersForPai is stored in the map as the value of the map, then the key of the map is ConvertiblePair, the encapsulation object of the original object and the target object. Then ConvertiblePair corresponds to a ConvertersForPair. If one ConvertersForPair corresponds to two GenericConverters, everyone will wonder how it is possible for one ConvertersForPair to correspond to two GenericConverters. So everyone imagine, what if the object and the target object are both interfaces or the object and the target object have multiple subclasses?

For example, the original object is class A, and the target object is class E. Class A has subclasses B, C, and D, and class E has F, G, and H. Now create a GenericConverter of AEGenericConverter to realize the conversion problem between connections. Over time, other modules have subclasses of A, AB, AC, AD. At this time, AEGenericConverter cannot do it. A new AAEGenericConverter must be required to convert A to E at the same time. This need is now a complex need in this system.

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

	private final Map<ConvertiblePair, ConvertersForPair> converters = new LinkedHashMap<ConvertiblePair, ConvertersForPair>(36);
add operation
public void add(GenericConverter converter) {
	// 调用GenericConverter.getConvertibleTypes方法得到Set<ConvertiblePair>,详细分析请看ConditionalGenericConverter 解读
	// 一个转换器可以把多个类型转换成多个类型
	Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();
	if (convertibleTypes == null) {
	   // 当convertibleTypes 为null的时候,就出现一个问题,怎么知道这个GenericConverter把什么转成什么,
	   // 那么需要converter 实现了ConditionalConverter的matches方法,进行识别是否可以转换
		Assert.state(converter instanceof ConditionalConverter,"Only conditional converters may return null convertible types");
		//加入全局Converters
		this.globalConverters.add(converter);
	}else {
	   // 一个转换器可以把多个类型转换成多个类型, 为什么出现,请看ConvertersForPair 出现的原因
		for (ConvertiblePair convertiblePair : convertibleTypes) {
		  // 通过ConvertiblePair 找到 ConvertersForPair
			ConvertersForPair convertersForPair = getMatchableConverters(convertiblePair);
			convertersForPair.add(converter);
		}
	}
}

private ConvertersForPair getMatchableConverters(ConvertiblePair convertiblePair) {
   // 通过convertiblePair 从缓存得到ConvertersForPair
	ConvertersForPair convertersForPair = this.converters.get(convertiblePair);
	if (convertersForPair == null) {
		// 如果缓存中没有,创建一个ConvertersForPair并加入缓存中。
		convertersForPair = new ConvertersForPair();
		this.converters.put(convertiblePair, convertersForPair);
	}
	return convertersForPair;
}
find operation
public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {
	// 搜索完整类型层次结构, 为什么出现,请看ConvertersForPair 出现的原因
	List<Class<?>> sourceCandidates = getClassHierarchy(sourceType.getType());
	List<Class<?>> targetCandidates = getClassHierarchy(targetType.getType());
	for (Class<?> sourceCandidate : sourceCandidates) {
		for (Class<?> targetCandidate : targetCandidates) {
			// 封装一个ConvertiblePair 对象作为 key
			ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);
			// 去缓存里面查询GenericConverter
			GenericConverter converter = getRegisteredConverter(sourceType, targetType, convertiblePair);
			if (converter != null) {
				return converter;
			}
		}
	}
	return null;
}

private GenericConverter getRegisteredConverter(TypeDescriptor sourceType,TypeDescriptor targetType, ConvertiblePair convertiblePair) {
	// 如果在converters与globalConverters,都有一个ByteBuffer 转 Array。在执行的时候,会选择匹配converters。
	// 检查特定注册转换器
	ConvertersForPair convertersForPair = this.converters.get(convertiblePair);
	if (convertersForPair != null) {
		GenericConverter converter = convertersForPair.getConverter(sourceType, targetType);
		if (converter != null) {
			return converter;
		}
	}
	// 检查动态匹配的条件转换器
	for (GenericConverter globalConverter : this.globalConverters) {
		if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) {
			return globalConverter;
		}
	}
	return null;
}

Summarize

  1. Class dependencies are divided into: operating system and management system
  2. Converter's ConvertersForPair class solves the identification relationship between multiple implementations of interfaces and multiple subclasses, and is the most difficult to understand in the entire system.
  3. The management system directly calls the subclass of GenericConverter, and then the subclass of GenericConverter performs conversion, such as direct conversion, or by calling the methods of Converter and ConverterFactory.
  4. Every time the GenericConverter is obtained, the matches of the ConditionalConverter will be called to judge whether the condition is met, and the current object will be obtained when the condition is reached.
  5. When add, the converter will be stored in the Converters class. 6. Converters are divided into globalConverters and converters
    1. The condition to add globalConverters is
      1. converter.getConvertibleTypes() returns not null
      2. converter also implements ConditionalConverter
    2. not added to globalConverters added to converters
  6. The GenericConversionService.converterCache will be emptied every time you add or delete it. The principle, please send the second point of summary analysis
  7. When getConverters, first identify whether GenericConversionService.converterCache exists, if not, find it from converters

mode used

singleton pattern

DefaultConversionService uses the singleton pattern

	private static volatile DefaultConversionService sharedInstance;


	public static ConversionService getSharedInstance() {
		if (sharedInstance == null) {
			synchronized (DefaultConversionService.class) {
				if (sharedInstance == null) {
					sharedInstance = new DefaultConversionService();
				}
			}
		}
		return sharedInstance;
	}

factory pattern

public interface ConverterFactory<S, R> {
	<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324982510&siteId=291194637