Spring 屬性注入(二)BeanWrapper 結構

Spring 屬性注入(二)BeanWrapper 結構

Spring 系列目錄(http://www.javashuo.com/article/p-hskusway-em.html)html

BeanWrapper 位於 org.springframework.beans 包中,默認實現爲 BeanWrapperImpl,提供分析和處理標準 JavaBean 用於 get 和 set 屬性,取得屬性描述,查詢屬性的讀/寫能力。java

beans 包還提供了一個 PropertyValues 用於保存多個屬性值,默認的實現 MutablePropertyValues。另外還有兩個有用的工具類,BeanUtils 和 PropertyAccessorUtils。spring

1、BeanWrapper 類圖

BeanWrapper 類圖

  • PropertyEditorRegistry PropertyEditor 註冊、查找。
  • TypeConverter 類型轉換,其主要的工做由 TypeConverterDelegate 這個類完成的。
  • PropertyAccessor 屬性讀寫。
  • ConfigurablePropertyAccessor 配置一些屬性,如設置 ConversionService、是否暴露舊值、嵌套注入時屬性爲 null 是否自動建立。
  • BeanWrapper 對 bean 進行封裝。
  • AbstractNestablePropertyAccessor 實現了對嵌套屬性注入的處理,其它實現見名知義就不介紹了。

BeanWrapper 的層次結構仍是比較清晰的,繼承於 ConfigurablePropertyAccessor 和 PropertyAccessor 接口。數組

有一點不太明白,爲何 BeanWrapper 要繼承於 PropertyEditorRegistry。從字面意義上來講,PropertyEditorRegistry 提供了 PropertyEditor,而 TypeConverter 進行類型轉換,和 BeanWrapper 不是繼承關係,使用組合感受更好。app

2、PropertyEditorRegistry

PropertyEditor 將 String 轉換爲其它類型,PropertyEditorRegistry 統一管理全部的 PropertyEditor 註冊和查找。編輯器

public interface PropertyEditorRegistry {
    // 1. 根據類型註冊 PropertyEditor
    void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor);

    // 2. 根據類型(requiredType)和屬性(propertyPath)註冊 PropertyEditor
    //    查找時優先根據 propertyPath 查找對應的 PropertyEditor,propertyPath 能夠爲嵌套屬性
    void registerCustomEditor(@Nullable Class<?> requiredType, 
        @Nullable String propertyPath, PropertyEditor propertyEditor);

    // 3. 根據類型和屬性查找 PropertyEditor
    PropertyEditor findCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath);
}

PropertyEditorRegistry 的實現類 PropertyEditorRegistrySupport 分析見這兩篇文章:ide

  1. PropertyEditorRegistrySupport 源碼分析
  2. 屬性編輯器 PropertyEditorSupport 在 Spring 中的應用

3、TypeConverter

TypeConverter 負責類型轉換,其主要的工做由 TypeConverterDelegate 這個類完成的。工具

public interface TypeConverter {
    // 1. value 轉換成 requiredType
    <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException;

    // 2. methodParam 同下
    <T> T convertIfNecessary(Object value, Class<T> requiredType,
            MethodParameter methodParam) throws TypeMismatchException;
    
    // 3. field 是 value 轉換成 requiredType 後須要賦值的 field 字段
    //    能夠從該 field 字段拿到其泛型信息,從而進一步判斷是否能夠轉換,畢竟 requiredType 只有 Class 信息
    <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field)
            throws TypeMismatchException;
}

TypeConverter 的實現類 TypeConverterSupport 的全部功能,實際是都是委託給 TypeConverterDelegate 完成的。源碼分析

4、PropertyAccessor

PropertyAccessor 提供了對 JavaBean 的基本操做。ui

public interface PropertyAccessor {
    boolean isReadableProperty(String propertyName);
    boolean isWritableProperty(String propertyName);

    Class<?> getPropertyType(String propertyName) throws BeansException;
    TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException;

    Object getPropertyValue(String propertyName) throws BeansException;

    void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException;
    void setPropertyValue(PropertyValue pv) throws BeansException;
    void setPropertyValues(Map<?, ?> map) throws BeansException;
    void setPropertyValues(PropertyValues pvs) throws BeansException;

    void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown)
            throws BeansException;
    void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
            throws BeansException;
}

PropertyAccessor 的實現類是 AbstractPropertyAccessor,這個類中 setPropertyValue 進行了處理,最終都是調用 setPropertyValue(String propertyName, Object value) 完成屬性注入。

4、ConfigurablePropertyAccessor

public interface ConfigurablePropertyAccessor extends 
        PropertyAccessor, PropertyEditorRegistry, TypeConverter {

    void setConversionService(@Nullable ConversionService conversionService);
    ConversionService getConversionService();

    // PropertyEditor 使用時是否暴露修改先後值
    void setExtractOldValueForEditor(boolean extractOldValueForEditor);
    boolean isExtractOldValueForEditor();
    
    // 嵌套注入時當屬性爲 null 時是否自動生成對象
    void setAutoGrowNestedPaths(boolean autoGrowNestedPaths);
    boolean isAutoGrowNestedPaths();
}

ConfigurablePropertyAccessor 的實現也類是 AbstractPropertyAccessor,這個類中默認 extractOldValueForEditor 和 autoGrowNestedPaths 都是 false,即不暴露舊值,也不支持嵌套注入時屬性爲 null 就自動建立對象。

5、BeanWrapper

public interface BeanWrapper extends ConfigurablePropertyAccessor {

    // @since 4.1 設置集合或數組自動生成對象的最大嵌套深度
    void setAutoGrowCollectionLimit(int autoGrowCollectionLimit);
    int getAutoGrowCollectionLimit();

    Object getWrappedInstance();
    Class<?> getWrappedClass();

    PropertyDescriptor[] getPropertyDescriptors();
    PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;
}
  1. Spring 屬性注入(三)AbstractNestablePropertyAccessor
  2. BeanWrapperImpl 源碼分析以下:

BeanWrapper 的實現類是 BeanWrapperImpl,主要完成了 JavaBean 的內省,包括 PropertyDescriptor 的獲取,屬性的賦值等。

(1) JavaBean 的內省

private CachedIntrospectionResults cachedIntrospectionResults;
// 獲取
private CachedIntrospectionResults getCachedIntrospectionResults() {
    if (this.cachedIntrospectionResults == null) {
        this.cachedIntrospectionResults = CachedIntrospectionResults.forClass(getWrappedClass());
    }
    return this.cachedIntrospectionResults;
}

JavaBean 的內省都是由 CachedIntrospectionResults 完成,經過 cachedIntrospectionResults 就能夠獲取對應屬性的 PropertyDescriptor。例以下面兩個方法:

@Override
public PropertyDescriptor[] getPropertyDescriptors() {
    return getCachedIntrospectionResults().getPropertyDescriptors();
}

@Override
public PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException {
    BeanWrapperImpl nestedBw = (BeanWrapperImpl) getPropertyAccessorForPropertyPath(propertyName);
    // 獲取屬性名稱
    String finalPath = getFinalPath(nestedBw, propertyName);
    PropertyDescriptor pd = nestedBw.getCachedIntrospectionResults().getPropertyDescriptor(finalPath);
    return pd;
}

(2) BeanPropertyHandler

@Override
protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) {
    PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
    return (pd != null ? new BeanPropertyHandler(pd) : null);
}

BeanPropertyHandler 是 BeanWrapperImpl 的內部類,是對 PropertyDescriptor 的封裝,完成對屬性的各類操做,如賦值。

(3) convertForProperty

convertForProperty 在 AbstractAutowireCapableBeanFactory#applyPropertyValues 屬性注入時使用

public Object convertForProperty(@Nullable Object value, String propertyName) throws TypeMismatchException {
    CachedIntrospectionResults cachedIntrospectionResults = getCachedIntrospectionResults();
    PropertyDescriptor pd = cachedIntrospectionResults.getPropertyDescriptor(propertyName);
    if (pd == null) {
        throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
                "No property '" + propertyName + "' found");
    }
    TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
    if (td == null) {
        td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd)));
    }
    // 父類 AbstractNestablePropertyAccessor 進行類型轉換
    return convertForProperty(propertyName, null, value, td);
}

// Property 也是對 PropertyDescriptor 封裝,在 Android 等環境中不存在 PropertyDescriptor 類
private Property property(PropertyDescriptor pd) {
    GenericTypeAwarePropertyDescriptor gpd = (GenericTypeAwarePropertyDescriptor) pd;
    return new Property(gpd.getBeanClass(), gpd.getReadMethod(), gpd.getWriteMethod(), gpd.getName());
}

天天用心記錄一點點。內容也許不重要,但習慣很重要!

相關文章
相關標籤/搜索