天天看點

Spring源碼:Converter及TypeConverter類解析

      • 三類Converter接口
      • TyperConverter
      • PropertyEditor
      • 總結

三類Converter接口

Spring提供了3種converter接口,分别是Converter、ConverterFactory和GenericConverter.一般用于1:1, 1:N, N:N的source->target類型轉化。

  • Converter接口
    public interface Converter<S, T> {
      // 将S轉換成T
    T convert(S source);
    }
               
  • GenericConverter接口:用于在兩種或更多種類型之間轉換的通用轉換器接口。
    public interface GenericConverter {
    
    Set<ConvertiblePair> getConvertibleTypes();
    
    Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
    
    /**
     * Holder for a source-to-target class pair.
     */
    final class ConvertiblePair {
        private final Class<?> sourceType;
        private final Class<?> targetType;
    }
    }
               
  • ConverterFactory接口:
    public interface ConverterFactory<S, R> {
    
    /**
     * Get the converter to convert from S to target type T, where T is also an instance of R.
     */
    <T extends R> Converter<S, T> getConverter(Class<T> targetType);
    
    }
               

TyperConverter

  • TypeConverter接口
    /**
     * 定義類型轉換方法的接口。通常(但不一定)與PropertyEditorRegistry接口一起實作
     * 通常接口TypeConverter的實作是基于非線程安全的PropertyEditors類,是以也不是線程安全的
     */
    public interface TypeConverter {
    
        /**
         * 将參數中的value轉換成requiredType類型
         * 從String到任何類型的轉換通常使用PropertyEditor類的setAsText方法或ConversionService中的Spring Converter
         */
        <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException;
    
        /**
         * 意義同上,增加了作為轉換目标的方法參數,主要用于分析泛型類型,可能是null
         */
        <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam) throws TypeMismatchException;
    
        /**
         * 意義同上,增加了轉換目标的反射field
         */
        <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field) throws TypeMismatchException;
    }
               
  • TypeConverterSupport抽象類:TypeConverter的基本實作類,同時也是BeanWrapperImpl類的依賴類。
    public abstract class TypeConverterSupport extends PropertyEditorRegistrySupport implements TypeConverter {
      // 委托給TypeConverterDelegate來轉換
    TypeConverterDelegate typeConverterDelegate;
    
    @Override
    public <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException {
        return doConvert(value, requiredType, null, null);
    }
    
    @Override
    public <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam) throws TypeMismatchException {
        return doConvert(value, requiredType, methodParam, null);
    }
    
    @Override
    public <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field) throws TypeMismatchException {
        return doConvert(value, requiredType, null, field);
    }
    
    private <T> T doConvert(Object value, Class<T> requiredType, MethodParameter methodParam, Field field) throws TypeMismatchException {
          if (field != null) {
              return this.typeConverterDelegate.convertIfNecessary(value, requiredType, field);
            } else {
              return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
            }
    }
    
    }
               
  • TypeConverterDelegate類:類型轉換的委托類,所有類型轉換的工作都由該類完成,即将屬性轉換為其他類型的Spring内部使用方法(内部實作: 先使用PropertyEditor轉換器器轉換,如果沒找到對應的轉換器器,會⽤ConversionService來進⾏行行對象轉換。)
    class TypeConverterDelegate {
        private final PropertyEditorRegistrySupport propertyEditorRegistry;
        private final Object targetObject;
        // ......
    }
               
  • SimpleTypeConverter源代碼
    /**不在特定目标對象上運作的TypeConverter接口的簡單實作。這是使用完整的BeanWrapperImpl執行個體來實作任意類型轉換需求的替代方法,同時使用相同的轉換算法(包括委托給PropertyEditor和ConversionService)。
     */
    public class SimpleTypeConverter extends TypeConverterSupport {
    
        public SimpleTypeConverter() {
            this.typeConverterDelegate = new TypeConverterDelegate(this);
            registerDefaultEditors();
        }
    }
               

PropertyEditor

  • PropertyEditor接口(jdk):用于字元串到其它對象的轉換,PropertyEditor是遵循javaBean規範的屬性處理器,其通過set方法設定屬性值,通過get方法擷取屬性值,相應的轉換邏輯就隐藏于其中。
  • **PropertyEditorSupport類(jdk):**PropertyEditor接口的預設實作。
    編寫自己的PropertyEditor,通常是繼承PropertyEditorSupport,而不用實作PropertyEditor,這樣就不用重寫PropertyEditor的所有方法了。
  • PropertyEditorRegistry接口: 封裝用于注冊JavaBeans PropertyEditors的方法。這是PropertyEditorRegistrar操作的中央接口。

    内部提供了三個函數用于PropertyEditor的注冊和查找

    public interface PropertyEditorRegistry {
    
      void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor);
    
      /**每個屬性路徑隻支援一個已注冊的自定義編輯器。對于集合/數組,不要同時為集合/數組和相同屬性上的每個元素注冊一個編輯器。例如,如果您想為“items[n].quantity”注冊一個編輯器(對于所有值n),您應該使用“items.quantity”作為這個方法“propertyPath”參數的值。**/
      // propertyPath:屬性的路徑(名稱或嵌套路徑),如果為給定類型的所有屬性注冊一個編輯器,則為null
    void registerCustomEditor(Class<?> requiredType, String propertyPath, PropertyEditor propertyEditor);
    
    PropertyEditor findCustomEditor(Class<?> requiredType, String propertyPath);
    
    }
               
  • **PropertyEditorRegistrySupport類:**PropertyEditorRegistry接口的預設實作,并且提供了預設editors和自定義editors的管理,主要作為服務BeanWrapperImpl的基類。
    public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
      // ......
    private ConversionService conversionService;
    
    private boolean defaultEditorsActive = false;
    
    private boolean configValueEditorsActive = false;
    
    private Map<Class<?>, PropertyEditor> defaultEditors;
    
    private Map<Class<?>, PropertyEditor> overriddenDefaultEditors;
    
    private Map<Class<?>, PropertyEditor> customEditors;
    
    private Map<String, CustomEditorHolder> customEditorsForPath;
      // ......
    }
               
  • CustomEditorConfigurer類:該類是BeanFactoryPostProcessor(BFPP類)的實作者,該類允許自定義屬性編輯器的友善注冊。常用注冊方式:
    <!--方式一-->
    <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
     <property name="propertyEditorRegistrars">
       <list>
         <bean class="mypackage.MyCustomDateEditorRegistrar"/>
         <bean class="mypackage.MyObjectEditorRegistrar"/>
       </list>
     </property>
    </bean>
    
    <!--方式二-->
    <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
     <property name="customEditors">
       <map>
         <entry key="java.util.Date" value="mypackage.MyCustomDateEditor"/>
         <entry key="mypackage.MyObject" value="mypackage.MyObjectEditor"/>
       </map>
     </property>
    </bean>
               
  • PropertyEditorRegistrar接口:用于使用屬性編輯器系統資料庫注冊自定義屬性編輯器的政策的接口,當需要在幾種不同的情況下使用同一組屬性編輯器時,這一點特别有用:編寫相應的注冊器并在每種情況下重用它。
    public interface PropertyEditorRegistrar {
      // 該方法傳入registry并添加自定義的PropertyEditor,一般情況下傳入的registry是BeanWrapperImpl的實體,是以就等于将自定義的PropertyEditor注入到BeanWrapperImpl裡面
    void registerCustomEditors(PropertyEditorRegistry registry);
    }
               

總結

  1. PropertyEditor用于字元串到其它對象的轉換,由于其局限性,spring提供了converter接口,由ConversionService來調用對外提供服務,而TypeConverter綜合了上述兩種轉換方式,交由TypeConverterDelegate來進行轉換。
  2. TypeConverterDelegater先使用PropertyEditor轉換器器轉換,如果沒找到對應的轉換器器,會⽤ConversionService來進⾏行行對象轉換。

繼續閱讀