第二章 二節spring-core之converter深刻解讀

前言

本章節深刻講解spring的converter使用與細節,幫助你們在項目裏面正確使用converter。converters是在項目開發裏面比較實用,切便利的功能,可是在複雜的業務中,須要架構師或者架構組設計,實現整套規範。源碼解讀沒法經過文字很詳細的解釋,詮釋。須要讀者屢次閱讀,深刻理解,組織邏輯,大腦慢慢造成整個流程。java

converter類關係體系

輸入圖片說明

從類實例圖中,能夠觀察到整個converter類關係體系分爲兩大塊。spring

  • 操做體系
  • 管理體系

操做體系

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

兩個很是簡單的類,Converter的子類是負責實現轉換,那ConverterFactory是用來幹什麼。 好比 有一個需求須要把數字型轉成字符串類型,可是Number的子類有Byte,Short,Integer,Long等等十多個,每一個有一個Converter實現(必須每一個都一個Converter,不然代碼很是很差管理,經過方法實現十分不優雅),這麼多如何進行管理。spring提供了一個解決方法經過工廠模式即便用ConverterFactory管理全部Converter緩存

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 {

}

先提早告訴你們架構

  • 管理體系直接調用 GenericConverter 的子類,而後GenericConverter的子類進行轉換,好比直接進行轉換,也能夠經過調用Converter與ConverterFactory的方法進行轉換。
  • 每次獲得GenericConverter,都會調用ConditionalConverter的matches 執行判斷是否達到條件,條件到達就會獲得當前對象 這是一個很奇怪,很是難以理解的設計。可是這個設計最重要的目的是爲了統一Converter與ConverterFactory的行爲,讓其保存一致。若是讓其保持一致的請看GenericConverter實現類ConverterFactoryAdapter與ConverterAdapter。還有這個設計是 保證可擴展性。

管理體系

輸入圖片說明

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

}

從聲明的方法能夠看出ConverterRegistry負責converter的添加與刪除ide

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

}

聲明的方法能夠看出ConversionService負責converter執行與是否有對應類型的converterui

ConfigurableConversionService
public interface ConfigurableConversionService extends ConversionService, ConverterRegistry {

}

嗯,ConfigurableConversionService就是擺看的,主要用於統一ConversionService與ConverterRegistry接口,方便實現類的操做this

GenericConversionService
public class GenericConversionService implements ConfigurableConversionService {
}

從class聲明中,能夠得知GenericConversionService實現了ConversionService和ConverterRegistry全部方法設計

先看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實現
@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);
}

從實現能夠分析到 全部方法code

  • 第一步是獲得原類型與目標類型,
  • 第二步調用getConverter方法,
  • 第三步處理的邏輯
注意
  1. NO_OP_CONVERTER 與 NO_MATCH 是不一樣的實例,可是行爲是同樣的。convert直接返回原數據
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實現內容
@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實現內容 很是簡單對象

  • 第一步是獲得原類型與目標類型,
  • 第二步 把對象轉換器與原類型,目標類型封裝成對應的GenericConverter不一樣子接口
  • 第三步 加入converters
  • 第四部 清空緩存
DefaultConversionService

DefaultConversionService註冊了不少通用Converter,到ConversionService裏面,這些通用的ConversionService,很好用。爲了讓博客有更多的可讀性,這裏不貼源代碼。若是你們有意願能夠去看看。

converters核心子體系

ConvertiblePairs

ConvertiblePair是一個簡單的實體類,重寫hashCode,equals,toString方法,做爲某個Converters.converters的key

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 是一個比較難理解的類。ConvertersForPair存在是作什麼的?

ConvertersForPai是當作map的value存入map,那麼這個map的key,是原對象與目標對象的封裝對象ConvertiblePair。那麼ConvertiblePair 對應一個ConvertersForPair。若是一個ConvertersForPair對應兩個GenericConverter,你們會想怎麼這麼可能出現一個ConvertersForPair對應兩個GenericConverter。那麼你們想象,若是對象與目標對象都是接口或者對象與目標對象都有多個子類怎麼辦?

好比 原對象是A類,, 目標對象是E類,。A類有子類B,C,D ,E類 有F,G,H,如今建立一個AEGenericConverter的GenericConverter實現覺接之間轉換問題。隨着時間的發展,其餘模塊有了A的子類AB,AC,AD。這個時候AEGenericConverter,就沒法作到。必須須要新的AAEGenericConverter,同時把A轉換E。這個須要目前是這個體系裏面對複雜的需求了。

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

	private final Map<ConvertiblePair, ConvertersForPair> converters = new LinkedHashMap<ConvertiblePair, ConvertersForPair>(36);
add操做
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操做
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;
}

總結

  1. 類依賴關係分爲:操做體系與管理體系
  2. converter的ConvertersForPair類解決了接口多實現也類多子類的識別關係,是整個體系中最難理解的。
  3. 管理體系直接調用 GenericConverter 的子類,而後GenericConverter的子類進行轉換,好比直接進行轉換,也能夠經過調用Converter與ConverterFactory的方法進行轉換
  4. 每次獲得GenericConverter,都會調用ConditionalConverter的matches 執行判斷是否達到條件,條件到達就會獲得當前對象
  5. add時候轉換器會存儲Converters類裏面, 6,Converters分 globalConverters與converters
    1. 添加 globalConverters的條件是
      1. converter.getConvertibleTypes()返回未null
      2. converter同時實現了ConditionalConverter
    2. 沒有添加到globalConverters添加到converters中
  6. 每次添加刪除都會清空GenericConversionService.converterCache緩存。原理請送第二點總結分析
  7. 當getConverters時,先識別GenericConversionService.converterCache是否存在,若是不存在從converters找

使用的模式

單例模式

DefaultConversionService使用了單例模式

private static volatile DefaultConversionService sharedInstance;


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

工廠模式

public interface ConverterFactory<S, R> {
	<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
相關文章
相關標籤/搜索