本章節深刻講解spring的converter使用與細節,幫助你們在項目裏面正確使用converter。converters是在項目開發裏面比較實用,切便利的功能,可是在複雜的業務中,須要架構師或者架構組設計,實現整套規範。源碼解讀沒法經過文字很詳細的解釋,詮釋。須要讀者屢次閱讀,深刻理解,組織邏輯,大腦慢慢造成整個流程。java
從類實例圖中,能夠觀察到整個converter類關係體系分爲兩大塊。spring
public interface Converter<S, T> { T convert(S source); }
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緩存
public interface GenericConverter { Set<ConvertiblePair> getConvertibleTypes(); Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType); }
public interface ConditionalConverter { boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType); }
public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter { }
先提早告訴你們架構
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
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
public interface ConfigurableConversionService extends ConversionService, ConverterRegistry { }
嗯,ConfigurableConversionService就是擺看的,主要用於統一ConversionService與ConverterRegistry接口,方便實現類的操做this
public class GenericConversionService implements ConfigurableConversionService { }
從class聲明中,能夠得知GenericConversionService實現了ConversionService和ConverterRegistry全部方法設計
/** *若是目標類型是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")); } }
@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
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; } } }
@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實現內容 很是簡單對象
DefaultConversionService註冊了不少通用Converter,到ConversionService裏面,這些通用的ConversionService,很好用。爲了讓博客有更多的可讀性,這裏不貼源代碼。若是你們有意願能夠去看看。
ConvertiblePair是一個簡單的實體類,重寫hashCode,equals,toString方法,做爲某個Converters.converters的key
final class ConvertiblePair { private final Class<?> sourceType; private final Class<?> targetType; }
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);
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; }
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; }
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); }