在實體化 bean 階段,我們從 BeanDefinition 得到的並不是我們最終想要的 Bean 實體,而是 BeanWrapper 實體,如下:

所以這裡 BeanWrapper 是一個從 BeanDefinition 到 Bean 直接的中間產物,我們可以稱它為”低階 bean“,在一般情況下,我們不會在實際專案中用到它。BeanWrapper 是 Spring 框架中重要的元件類,它就相當於一個代理類,Spring 委託 BeanWrapper 完成 Bean 屬性的填充工作。在 bean 實體被 InstantiatioonStrategy 創建出來後,Spring 容器會將 Bean 實體透過 BeanWrapper 包裹起來,是透過 BeanWrapper.setWrappedInstance() 完成的,如下:

beanInstance 就是我們實體出來的 bean 實體,透過構造一個 BeanWrapper 實體物件進行包裹,如下:
public BeanWrapperImpl(Object object) {super(object);}protected AbstractNestablePropertyAccessor(Object object) {registerDefaultEditors();setWrappedInstance(object);}
下麵小編就 BeanWrapper 來進行分析說明,先看整體的結構:

從上圖可以看出 BeanWrapper 主要繼承三個核心介面:PropertyAccessor、PropertyEditorRegistry、TypeConverter。
PropertyAccessor
可以訪問屬性的通用型介面(例如物件的 bean 屬性或者物件中的欄位),作為 BeanWrapper 的基礎介面。
public interface PropertyAccessor {String NESTED_PROPERTY_SEPARATOR = ".";char NESTED_PROPERTY_SEPARATOR_CHAR = '.';String PROPERTY_KEY_PREFIX = "[";char PROPERTY_KEY_PREFIX_CHAR = '[';String PROPERTY_KEY_SUFFIX = "]";char PROPERTY_KEY_SUFFIX_CHAR = ']';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;}
就上面的原始碼我們可以分解為四類方法:
isReadableProperty():判斷指定 property 是否可讀,是否包含 getter 方法isWritableProperty():判斷指定 property 是否可寫,是否包含 setter 方法getPropertyType():獲取指定 propertyName 的型別setPropertyValue():設定指定 propertyValue
PropertyEditorRegistry
用於註冊 JavaBean 的 PropertyEditors,對 PropertyEditorRegistrar 起核心作用的中心介面。由 BeanWrapper 擴充套件,BeanWrapperImpl 和 DataBinder 實現。
public interface PropertyEditorRegistry {void registerCustomEditor(Class> requiredType, PropertyEditor propertyEditor);void registerCustomEditor(@Nullable Class> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor);@NullablePropertyEditor findCustomEditor(@Nullable Class> requiredType, @Nullable String propertyPath);}
根據介面提供的方法,PropertyEditorRegistry 就是用於 PropertyEditor 的註冊和發現,而 PropertyEditor 是 Java 內省裡面的介面,用於改變指定 property 屬性的型別。
TypeConverter
定義型別轉換的介面,通常與 PropertyEditorRegistry 介面一起實現(但不是必須),但由於 TypeConverter 是基於執行緒不安全的 PropertyEditors ,因此 TypeConverters 本身也不被視為執行緒安全。 這裡小編解釋下,在 Spring 3 後,不在採用 PropertyEditors 類作為 Spring 預設的型別轉換介面,而是採用 ConversionService 體系,但 ConversionService 是執行緒安全的,所以在 Spring 3 後,如果你所選擇的型別轉換器是 ConversionService 而不是 PropertyEditors 那麼 TypeConverters 則是執行緒安全的。
public interface TypeConverter {<T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException;<T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam)throws TypeMismatchException;<T> T convertIfNecessary(Object value, Class<T> requiredType, Field field)throws TypeMismatchException;}
BeanWrapper 繼承上述三個介面,那麼它就具有三重身份:
- 屬性編輯器
- 屬性編輯器登錄檔
- 型別轉換器
BeanWrapper 繼承 ConfigurablePropertyAccessor 介面,該介面除了繼承上面介紹的三個介面外還集成了 Spring 的 ConversionService 型別轉換體系。
public interface ConfigurablePropertyAccessor extends PropertyAccessor, PropertyEditorRegistry, TypeConverter {void setConversionService(@Nullable ConversionService conversionService);@NullableConversionService getConversionService();void setExtractOldValueForEditor(boolean extractOldValueForEditor);boolean isExtractOldValueForEditor();void setAutoGrowNestedPaths(boolean autoGrowNestedPaths);boolean isAutoGrowNestedPaths();}
setConversionService() 和 getConversionService() 則是用於整合 Spring 的 ConversionService 型別轉換體系。
BeanWrapper
Spring 的 低階 JavaBean 基礎結構的介面,一般不會直接使用,而是透過 BeanFactory 或者 DataBinder 隱式使用。它提供分析和操作標準 JavaBeans 的操作:獲取和設定屬性值、獲取屬性描述符以及查詢屬性的可讀性/可寫性的能力。
public interface BeanWrapper extends ConfigurablePropertyAccessor {void setAutoGrowCollectionLimit(int autoGrowCollectionLimit);int getAutoGrowCollectionLimit();Object getWrappedInstance();Class> getWrappedClass();PropertyDescriptor[] getPropertyDescriptors();PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;}
下麵幾個方法比較重要:
個物件有4個方法比較重要:
getWrappedInstance():獲取包裝物件的實體。getWrappedClass():獲取包裝物件的型別。getPropertyDescriptors():獲取包裝物件所有屬性的 PropertyDescriptor 就是這個屬性的背景關係。getPropertyDescriptor():獲取包裝物件指定屬性的背景關係。
BeanWrapperImpl
BeanWrapper 介面的預設實現,用於對Bean的包裝,實現上面介面所定義的功能很簡單包括設定獲取被包裝的物件,獲取被包裝bean的屬性描述器
BeanWrapper 體系相比於 Spring 中其他體系是比較簡單的,它作為 BeanDefinition 向 Bean 轉換過程中的中間產物,承載了 bean 實體的包裝、型別轉換、屬性的設定以及訪問等重要作用。
知識星球