在實體化 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);
@Nullable
PropertyEditor 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);
@Nullable
ConversionService 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 實體的包裝、型別轉換、屬性的設定以及訪問等重要作用。