(spring-第11回【IoC基礎篇】)BeanWrapper--實例化Bean的第四大利器


重復是理解和記憶的最好方法。在講實例化Bean的每個步驟之前,我都會先復習一下Bean實例化的整個過程:

 

結合圖片我們回顧一下具體的過程:

  1. ResourceLoader加載配置信息,
  2. 由BeanDefinitionReader讀取並解析<bean>標簽,並將<bean>標簽的屬性都轉換為BeanDefinition對應的屬性,並注冊到BeanDefinitionRegistry注冊表中。
  3. 容器掃描注冊表,通過反射機制獲取BeanFactoryPostProcessor類型的工廠后處理器,並用這個工廠后處理器對BeanDefinition進行加工。
  4. 取出加工過的BeanDefinition,使用InstantiationStrategy實例化Bean。
  5. BeanWrapper結合BeanDefinitionRegistry和PropertyEditorRegistry對Bean的屬性賦值。

今天我們將介紹的就是第五步。開門見山,BeanWrapper的功能:

spring通過BeanWrapper完成屬性的配置工作。具體表現為:

  1. 從BeanDefinitionRegistry注冊表中取出尚未進行屬性配置的BeanDefinition,獲取Bean屬性的配置信息,
  2. 使用屬性編輯器對這些配置信息進行轉換得到Bean屬性的值,
  3. 最后對Bean通過反射機制設置屬性值。

下面是BeanWrapper的繼承結構:

 

從上面的結構可以看出,BeanWrapperImpl(BeanWrapper的實現類)有兩個頂級接口,分別是:PropertyEditorRegistry和PropertyAccessor,前者是屬性編輯器,負責將配置文件中bean屬性的字面值轉換為bean具體的屬性值。后者定義了各種訪問bean屬性的方法。所以BeanWrapperImpl具有三重身份:

  1.  Bean包裹器:(顧名思義)

        下面代碼是BeanWrapperImpl初始化時要執行的方法,而參數中的object就是包裹的bean對象。

        其中第8行就是把object.getClass()保存在cachedIntrospectionResults 屬性中,該屬性是CachedIntrospectionResults類的實例,

        CachedIntrospectionResults是負責緩存屬性描述器(PropertyDescriptor)信息的。  

        object是對象的實例,而object.getClass()則獲取的是實例對應的類的描述信息,那么cachedIntrospectionResults 拿到這個實例類的描述信息class,就可以通過反射機制來訪問該class里面的所有屬性了,最后封裝成PropertyDescriptor。

        屬性描述器(PropertyDescriptor)是java.beans.PropertyDescriptor包里的類,用來描述java bean的屬性(一個描述器描述一個屬性),這個屬性是JavaBean通過一對入口方法導出的。

        BeanWrapperImpl利用屬性描述器信息結合屬性編輯器來設置屬性。

1 public void setWrappedInstance(Object object, String nestedPath, Object rootObject) {
2         Assert.notNull(object, "Bean object must not be null");
3         this.object = object;
4         this.nestedPath = (nestedPath != null ? nestedPath : "");
5         this.rootObject = (!"".equals(this.nestedPath) ? rootObject : object);
6         this.nestedBeanWrappers = null;
7         this.typeConverterDelegate = new TypeConverterDelegate(this, object);
8         setIntrospectionClass(object.getClass());
9     }
1 protected void setIntrospectionClass(Class clazz) {
2         if (this.cachedIntrospectionResults != null &&
3                 !clazz.equals(this.cachedIntrospectionResults.getBeanClass())) {
4             this.cachedIntrospectionResults = null;
5         }
6     }

 

  

   2.  屬性訪問器:即PropertyAccessor,這個接口有很多方法,諸如:setPropertyValue、setPropertyValues等,BeanWrapperImpl通過這些方法來設置bean屬性的值。

 

3.  屬性編輯器注冊表:(負責取出屬性編輯器,BeanWrapperImpl結合屬性編輯器來設置屬性)。

 

下面是BeanWrapperImpl的某個構造函數,一開始就調用了從屬性編輯器那里繼承過來的registerDefaultEditors方法,該方法自動注冊加載spring默認的屬性編輯器們。

 

1 public BeanWrapperImpl(Object object) {
2         registerDefaultEditors();
3         setWrappedInstance(object);
4     }

 

BeanWrapperImpl完成Bean屬性的配置工作之后,接下來還需要Bean后處理器(實現了BeanPostProcessor接口的Bean)繼續對Bean實例進行加工,直到裝配出一個准備就緒的Bean,把肉放到碗里等萌寶來吃。

由於本文未對代碼進行詳細解讀,所以其中會有沒有講到的地方,比如,屬性編輯器具體是怎樣的?如何對bean的屬性進行編輯?下一篇博文將會詳細介紹。

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM