1. 程式人生 > >spring 原始碼研究---bean包--BeanWapper TypeCoverter PropertyEditorRegistrySupport BeanInfo PropertyValue

spring 原始碼研究---bean包--BeanWapper TypeCoverter PropertyEditorRegistrySupport BeanInfo PropertyValue

#####################   PropertyValue  ############################
AttributeAccessor定義了訪問屬性訪問器
AttributeAccessorSupport使用hash表來管理屬性訪問器
BeanMetadataElement介面攜帶了包含bean元資料元素的source物件
BeanMetadataAttribute類持有bean物件中一個key/value屬性,跟蹤source物件
BeanMetadataAttributeAccessor繼承了AttributeAccessorSupport類,實現了BeanMetadataElement介面,
它不僅擁有屬性訪問器,它把屬性值設定為BeanMetadataAttribute型別,把key設定為BeanMetadataAttribute的key,它還可以跟蹤source物件
PropertyValue繼承自BeanMetadataAttributeAccessor
儲存bean物件中的資訊及值,使用一個物件,而不是讓所有屬性儲存在Map物件中,它允許了更大的靈活性,並且能都處理索引屬性來優化
它可以是簡單的包含屬性,不需要進行解析後放入        
PropertyValues介面持有一個或多個PropertyValue物件,通常更新指定的bean。
MutablePropertyValues實現了PropertyValues介面。
把所有PropertyValue放入了List集合中,可以當作集合來管理PropertyValue物件,
它提供了構造器可以對來自List Map PropertyValues等持有PropertyValue物件的集合中進行深度拷貝。

/**
 *################################ BeanWrapper#############################
 * PropertyAccessor介面定義了class類中欄位的訪問和設定功能
 * 判斷該欄位是否支援讀 寫
 * 通過欄位名取得對應的型別
 * 通過欄位名得到對應的物件
 * 通過欄位名得到型別描述TypeDescipter
 * 通過name,vaule或Map或PropertyValue或PropertyValues來設定欄位值
 * 在設定PropertyValues集合屬性時,可以設定是否忽略不需要的元素或無法驗證的元素
 *
 * ConfigurablePropertyAccessor介面繼承了PropertyAccessor介面 PropertyEditorRegistry介面 和TypeConverter介面
 * 它就包含屬性訪問器、編輯器管理、及型別轉換功能
 * 它自己設定配置轉換器服務ConversionService
 * 設定了是否需要提取編輯器設定的舊值
 * AbstractPropertyAccessor抽象類實現了TypeConverterSupport和ConfigurablePropertyAccessor
 * 定義了訪問器的set get 主要結構,主要的實現有子類完成,這是典型的模板方法。
 *
 * 定義bean物件,
 * 定義bean物件的.之前的根路徑物件,如果物件是集合,定義每個元素在集合中的路徑
 * 定義了快取當前訪問器的map key nestedPath value是該類下的下一個訪問器
 * 構造器
 * 1.是否使用預設的編輯器
 * 2.預設建構函式為使用預設的編輯器
 * 3.給定物件或型別
 * 構造器根據設定的值構造該物件
 * 可以訪問該物件例項
 * 可以訪問該物件型別
 * 可以訪問該物件在元素集合中的位置屬性
 * 可以訪問該物件訪問器的根物件 .最前面的對像及根物件型別
 *
 *
 * 設定值 String propertyName, Object value
 * 1:通過屬性名轉換為PropertyTokenHolder物件,這個物件包含了
 * actualName真實的物件名如果是集合就是[]前面的物件名,否則是propertyName
 * 如果是集合canonicalName=actualName[key1][key2]否則是propertyName
 * 包含了keys的集合 key1 key2
 * 然後使用這actualName得到PropertyHandler 這個功能有子類實現
 * PropertyHandler是什麼呢?
 * PropertyHandler是定義在AbstractNestablePropertyAccessor內部的一個抽象類
 * 它用於持有一個物件屬性的各種資源,它的大部分實現是有子類完成的,有見模板方法
 * 屬性資源是通過反射還是Javabean方式獲取有子類來實現。
 * 有了物件例項和型別就可以通過反射的取的屬性相關的資訊 子類來實現 填充物件
 * 繼續回到上面得到PropertyHandler以後就可以取的該屬性的值,
 * 如果子類沒有實現 則建立一個新的物件返回
 * 然後建立一個AbstractNestablePropertyAccessor或則從快取中取的
 * 遞迴查詢每個訪問器。
 * 查詢到放入PropertyValue,包含了PropertyTokenHolder,如果是陣列就可以定位該地方設定值了
 *
 * 查詢
 * mb[0].bean1.bean2.order[2]
 * //首先根據 mb[0].bean1.bean2.order[2] 屬性名,取mb欄位通過反射取的值,
//然後取的集合中的第0個物件這裡就叫root物件,
//使用引數root物件、下一個屬性路徑bean1.bean2.order[2]和父訪問器dfa 來構造一個新的訪問器
//遞迴以上方式,最後取的值。
 *
 * BeanWrapperImpl和DirectFieldAccessor都實現了AbstractNestablePropertyAccessor
 * DirectFieldAccessor使用了反射的方式設定和取值的
 * BeanWrapperImpl使用的時Javabean技術訪問BeanInfo的PropertyDescripter
 *
 */
################### BeanInfo ###################################################
//建立BeanInfo使用了簡單工廠BeanInfoFactory,
//由子類ExtendedBeanInfoFactory實現,該類並且繼承了排序介面Ordered對BeanInfo設定序號
//ExtendedBeanInfoFactory內部使用了ExtendedBeanInfo來建立BeanInfo
//ExtendedBeanInfo使用了裝飾器模式對從Introspector#getBeanInfo得到BeanInfo物件進行了裝飾。
//裝飾原因:主要對java bean支援寫方法即set方法的返回值為void不支援set方法的返回值為非void
//由於需要建立模式等,會返回當前物件所以需要支援該方式。

//注意ExtendedBeanInfo只支援此方式

/*例如:
 * public Bean setFoo(Foo foo) {
 *         this.foo = foo;
 *         return this;
 * }
 *ExtendedBeanInfo繼承BeanInfo 通過構造器委託該物件實現大部分方法,幷包裝了PropertyDescriptor[]返回物件
 * 經過包裝後的PropertyDescriptor[],很好的支援了每個返回值不為void的set方法取的的PropertyDescriptor物件
 * 裝飾過程:
 * 1.拷貝BeanInfo物件的PropertyDescriptor到Set集合中,
 * 2.迴圈MethodDescriptor[]判斷方式是否符合 set(引數1)或,setXx(引數1,引數2)
 * 1.方法名稱字數大於3
 * 2.set開頭
 * 3.方法訪問許可權為public
 * 4.非void或者是靜態方法
 * 5.引數為一個 或者如果是陣列屬性 可以兩個引數,但第一個必須是int型別
 *
 * 如果符合擷取方法名setXx為xx和第一個引數型別去匹配Set集合中的PropertyDescriptor
 * 是否存在 如果存在,就設定PropertyDescriptor的write方法為該方法。
 * 否則就建立一個PropertyDescriptor放入Set集合中。
 * 最後在重寫public PropertyDescriptor[] getPropertyDescriptors()時,
 * 把Set集合返回。
 * 經過包裝spring可以只支援set方法就取的PropertyDescriptor
 * 說了這麼多,BeanInfo到底怎麼建立的?
 * 是由Introspector.getBeanInfo(xx.class)方法建立
 * 由於工廠只建立包含典型的set方法返回的非void型別,
 * 所以如果是正常的就是用Introspector.getBeanInfo(xx.class)建立Beanfo
 *
 * 在類中,如果是泛型屬性會存在一個set型別的橋樑方法
 * 需要對BeanInfo中PropertyDescriptor[]陣列的元素做寫方法和讀方法做處理
 * GenericTypeAwarePropertyDescriptor繼承了PropertyDescriptor類,
 * 它對寫方法和讀方法出現的橋樑方法做了處理,併兼容了set方法比如set方法是private的。
 * GenericTypeAwarePropertyDescriptor作為一個PropertyDescriptor放入快取map中。
 * key是屬性名字,value就是這個GenericTypeAwarePropertyDescriptor物件
 * 可以使用map得到集合 陣列或使用屬性名查詢PropertyDescriptor
 * 通過Class物件獲得查詢包裝後的適合spring的BeanInfo及PropertyDescriptor[]
 * 對於這些結果需要用快取存起來,因為訪問底層是有消耗的。
 * CachedIntrospectionResults就是用來快取內省結構資訊,它接受一個或多個類載入器
 * 來載入class型別。
 * 如果給定的Class型別在它接受的類載入器中(或者Class型別類載入器與CachedIntrospectionResults對應的類載入器屬於同一類載入器或是同一父類載入器)
 * ,則把Class物件作為key CachedIntrospectionResults作為值
 * 快取在一個執行緒安全強引用的map中(strongClassCache)。
 * 否則快取在另一個執行緒安全弱引用的map中(softClassCache)。
 * 通過CachedIntrospectionResults的靜態方法 static CachedIntrospectionResults forClass(Class<?> beanClass)
 * 首先從強引用快取中取,沒有則然後從弱引用中取,如何還沒有則使用,則new CachedIntrospectionResults物件建立BeanInfo資訊。
 * 放入快取,返回CachedIntrospectionResults,就可以得到beanInfo資訊 或類載入,或PropertyDescriptor[]等資訊。
 * 大概資料結構:
 *  * -Class<?>{
*                         CachedIntrospectionResults{
*                             ClassLoader{
*                                 ClassLoader1,
*                                 ClassLoader2,
*                             }
*                             BeanInfo,
*                             PropertyDescriptors[
*                                PropertyDescriptor,
*                                PropertyDescriptor
*                            ],
*                            TypeDescriptor{
*                                PropertyDescriptor:TypeDescriptor,
*                                PropertyDescriptor:TypeDescriptor,
*                            }
*                         },
*                       }

/**########################### PropertyEditorRegistry  ##############################
 * PropertyEditorRegistry介面定義了PropertyEditor編輯器的註冊服務
 * 主要功能為註冊定製的PropertyEditor編輯器和查詢PropertyEditor編輯器
 * 以PropertyEditor的實現類Class為key,編輯器為value放入字典中。
 * 對於集合和陣列中對應的元素則以該元素的屬性路徑及propertyPath為key,
 * value為(該集合實現了Class為key,該元素的編輯器為value)放入字典中, propertyPath=items[n]
 * 對於集合每個元素都有單一的註冊編輯器,不註冊集合或陣列相同元素為同一編輯器
 * 如果要註冊items[n].quantity中的所有元素則使用items.quantity
 *
 *
 * PropertyEditorRegistrySupport類實現了PropertyEditorRegistry介面
 * 它提供了預設編輯器註冊和定製編輯器
 * 它使用了5種登錄檔
 * 1.預設登錄檔
 * 包含了大量spring定義的屬性編輯器,有基本包裝型別,集合及常用的類屬性編輯器
 * 2.覆蓋預設的登錄檔
 * 如果預設登錄檔種的編輯器和自定義的編輯器有重複則優先使用自定義的
 * 3.定製登錄檔
 * key為編輯器實現PropertyEditor的Class類,value為實現物件
 * 4.定製propertyPath登錄檔
 * propertyPath是集合物件中元素的屬性路徑作為key 比如:item[5]
 * (key為編輯器實現PropertyEditor的Class類,value為實現物件)
 * (使用CustomEditorHolder物件持有)作為propertyPath的value.
 * 5.用於快取定製登錄檔
 * 加快登錄檔訪問速度,專門為定製登錄檔做了一個快取。
 *
 * 它給子類提供了註冊預設編輯器的方法
 * 它提供了轉換型別服務
 * 它提供了使用者可以啟用預設編輯器的功能,預設沒有啟用
 * 它通過給定的Class編輯器和propertyPath路徑來註冊到不同的登錄檔中(放入map中)
 * 它通過給定的Class和propertyPath查詢登錄檔中的編輯器返回
 *
 */
/**########################## TypeCoverter ####################
 * spring封裝了自動的轉換的功能,結合了TypeCoverter
 * TypeConverter介面定義了型別轉換的方法,通常的(但不需要的)子類也要實現PropertyEditorRegistry
 * 轉換通常使用PropertyEditor的setAsText或者使用spring的ConversionService轉換服務
 * 通常把一個物件轉化為給定的型別
 * TypeConverterSupport實現了TypeConverter和PropertyEditorRegistry它沒有做實質性的實現,
 * 直接把實現委託給TypeConverterDelegate類來處理
 * TypeConverterDelegate它認認真真的完成委託人的轉換型別任務。它需要有屬性註冊服務PropertyEditorRegistrySupport的支援
 * BeanWrapperImpl和SimpleTypeConverter子類把自己作為PropertyEditorRegistrySupport委託給TypeConverterDelegate處理
 * 因為不同的實現有不同編輯屬性登錄檔
 *
 * convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<T> requiredType,
 * TypeDescriptor typeDescriptor)
 * propertyName 登錄檔中的集合屬性地址
 * oldValue
 * newValue    要轉換的物件
 * requiredType  轉換後需要的型別
 * typeDescriptor 轉換後的型別描述,比如有annotation的方法引數或欄位包含的資訊
 *===轉換器轉換
 * 通過propertyName requiredType來查詢一個屬性編輯器
 * 取的註冊編輯器服務設定的ConversionService轉換物件
 * 如果屬性編輯器為空並且ConversionService不為空並且newValue不為空並且typeDescriptor不為空
 * 則使用typeDescriptor取的newValue的TypeDescriptor,
 * 使用ConversionService.convert判斷要轉換物件的TypeDescriptor和目標typeDescriptor能否轉換
 * 如果能轉換直接使用ConversionService轉換返回轉換型別
 *
 * ==編輯器轉換及集合轉換
 * 否則使用編輯器轉換
 *    newValue requiredType typeDescriptor         
 * 1.String --    集合    - > 列舉             String[]  
 * 如果編輯器不為空或者newValue不是來自於requiredType
 *         如果requiredType是一個集合型別,newValue為一個String型別,並且typeDescriptor是列舉型別
 *         則使用,分割String型別後作為String陣列設定newValue為String陣列,使用編輯器進行編輯
 *      把newValue進行編輯器先轉換一次
 *
 * 如果requiredType不為空,並且編輯後convertedValue不為空,
 * 1.convertedValue是Object型別直接返回
 * 2.requiredType是陣列
 * 3.convertedValue是集合
 * 4.convertedValue是Map
 * 5.convertedValue是陣列型別,就包含一個元素,就返回該元素
 * 6.requiredType如果是String型別,包裝convertedValue作為物件返回
 * 7.如果convertedValue是String 但requiredType不是String的例項
 * 試著使用requiredType的建構函式(String convertedValue)建立物件例項
 * 或者requiredType是Number型別的就轉換
 * 或者轉換為列舉
 *
 *陣列的轉換:
 *    如果轉換物件型別為Collection
 *    根據轉換物件集合,建立一個需要型別陣列
 *    迴圈轉換物件集合,使用上面的convertIfNecessary方法來轉換,其中propertyName=propertyName[i]
 *    這個可以用來查詢編輯器登錄檔,需要型別陣列新增每一個轉換後的返回元素
 *     返回這個型別陣列
 *  如果是轉換型別是陣列, 並且需要型別也是該陣列,並且編輯器中不包含陣列中元數的轉換器,則直接返回該轉換陣列
 *  否則迴圈轉換
 *  
 *  如果 轉換物件就一個物件 直接建立一個需要型別的陣列把這個轉換物件新增進入返回
 *  
 *集合和陣列相似
 *
 * SimpleTypeConverter設定了預設編輯器登錄檔,並且把轉換型別任務委託給TypeConverterDelegate處理
 *
*/