歡迎光臨
每天分享高質量文章

【死磕 Spring】—– IOC 之分析 BeanWrapper

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

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

beanInstance 就是我們實體出來的 bean 實體,通過構造一個 BeanWrapper 實體物件進行包裹,如下:

  1. public BeanWrapperImpl(Object object) {
  2.  super(object);
  3. }
  4. protected AbstractNestablePropertyAccessor(Object object) {
  5.  registerDefaultEditors();
  6.  setWrappedInstance(object);
  7. }

下麵小編就 BeanWrapper 來進行分析說明,先看整體的結構:

從上圖可以看出 BeanWrapper 主要繼承三個核心接口:PropertyAccessor、PropertyEditorRegistry、TypeConverter。

PropertyAccessor

可以訪問屬性的通用型接口(例如物件的 bean 屬性或者物件中的欄位),作為 BeanWrapper 的基礎接口。

  1. public interface PropertyAccessor {
  2. String NESTED_PROPERTY_SEPARATOR = ".";
  3. char NESTED_PROPERTY_SEPARATOR_CHAR = '.';
  4. String PROPERTY_KEY_PREFIX = "[";
  5. char PROPERTY_KEY_PREFIX_CHAR = '[';
  6. String PROPERTY_KEY_SUFFIX = "]";
  7. char PROPERTY_KEY_SUFFIX_CHAR = ']';
  8. boolean isReadableProperty(String propertyName);
  9. boolean isWritableProperty(String propertyName);
  10. Class> getPropertyType(String propertyName) throws BeansException;
  11. TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException;
  12. Object getPropertyValue(String propertyName) throws BeansException;
  13. void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException;
  14. void setPropertyValue(PropertyValue pv) throws BeansException;
  15. void setPropertyValues(Map, ?> map) throws BeansException;
  16. void setPropertyValues(PropertyValues pvs) throws BeansException;
  17. void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown)
  18.   throws BeansException;
  19. void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
  20.   throws BeansException;
  21. }

就上面的原始碼我們可以分解為四類方法:

  • isReadableProperty():判斷指定 property 是否可讀,是否包含 getter 方法
  • isWritableProperty():判斷指定 property 是否可寫,是否包含 setter 方法
  • getPropertyType():獲取指定 propertyName 的型別
  • setPropertyValue():設置指定 propertyValue

PropertyEditorRegistry

用於註冊 JavaBean 的 PropertyEditors,對 PropertyEditorRegistrar 起核心作用的中心接口。由 BeanWrapper 擴展,BeanWrapperImpl 和 DataBinder 實現。

  1. public interface PropertyEditorRegistry {
  2. void registerCustomEditor(Class> requiredType, PropertyEditor propertyEditor);
  3. void registerCustomEditor(@Nullable Class> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor);
  4. @Nullable
  5. PropertyEditor findCustomEditor(@Nullable Class> requiredType, @Nullable String propertyPath);
  6. }

根據接口提供的方法,PropertyEditorRegistry 就是用於 PropertyEditor 的註冊和發現,而 PropertyEditor 是 Java 內省裡面的接口,用於改變指定 property 屬性的型別。

TypeConverter

定義型別轉換的接口,通常與 PropertyEditorRegistry 接口一起實現(但不是必須),但由於 TypeConverter 是基於執行緒不安全的 PropertyEditors ,因此 TypeConverters 本身也不被視為執行緒安全。 這裡小編解釋下,在 Spring 3 後,不在採用 PropertyEditors 類作為 Spring 預設的型別轉換接口,而是採用 ConversionService 體系,但 ConversionService 是執行緒安全的,所以在 Spring 3 後,如果你所選擇的型別轉換器是 ConversionService 而不是 PropertyEditors 那麼 TypeConverters 則是執行緒安全的。

  1. public interface TypeConverter {
  2.    <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException;
  3.    <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam)
  4.            throws TypeMismatchException;
  5.    <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field)
  6.            throws TypeMismatchException;
  7. }

BeanWrapper 繼承上述三個接口,那麼它就具有三重身份:

  • 屬性編輯器
  • 屬性編輯器註冊表
  • 型別轉換器

BeanWrapper 繼承 ConfigurablePropertyAccessor 接口,該接口除了繼承上面介紹的三個接口外還集成了 Spring 的 ConversionService 型別轉換體系。

  1. public interface ConfigurablePropertyAccessor extends PropertyAccessor, PropertyEditorRegistry, TypeConverter {
  2. void setConversionService(@Nullable ConversionService conversionService);
  3. @Nullable
  4. ConversionService getConversionService();
  5. void setExtractOldValueForEditor(boolean extractOldValueForEditor);
  6. boolean isExtractOldValueForEditor();
  7. void setAutoGrowNestedPaths(boolean autoGrowNestedPaths);
  8. boolean isAutoGrowNestedPaths();
  9. }

setConversionService() 和 getConversionService() 則是用於集成 Spring 的 ConversionService 型別轉換體系。

BeanWrapper

Spring 的 低級 JavaBean 基礎結構的接口,一般不會直接使用,而是通過 BeanFactory 或者 DataBinder 隱式使用。它提供分析和操作標準 JavaBeans 的操作:獲取和設置屬性值、獲取屬性描述符以及查詢屬性的可讀性/可寫性的能力。

  1. public interface BeanWrapper extends ConfigurablePropertyAccessor {
  2. void setAutoGrowCollectionLimit(int autoGrowCollectionLimit);
  3. int getAutoGrowCollectionLimit();
  4. Object getWrappedInstance();
  5. Class> getWrappedClass();
  6. PropertyDescriptor[] getPropertyDescriptors();
  7. PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;
  8. }

下麵幾個方法比較重要:

個物件有4個方法比較重要:

  • getWrappedInstance():獲取包裝物件的實體。
  • getWrappedClass():獲取包裝物件的型別。
  • getPropertyDescriptors():獲取包裝物件所有屬性的 PropertyDescriptor 就是這個屬性的背景關係。
  • getPropertyDescriptor():獲取包裝物件指定屬性的背景關係。

BeanWrapperImpl

BeanWrapper 接口的預設實現,用於對Bean的包裝,實現上面接口所定義的功能很簡單包括設置獲取被包裝的物件,獲取被包裝bean的屬性描述器

BeanWrapper 體系相比於 Spring 中其他體系是比較簡單的,它作為 BeanDefinition 向 Bean 轉換過程中的中間產物,承載了 bean 實體的包裝、型別轉換、屬性的設置以及訪問等重要作用。

赞(0)

分享創造快樂