1. 概述
commons-beanutil開源庫是apache組織的一個基礎的開源庫。為apache中很多類提供工具方法。學習它是學習其它開源庫實現的基礎。
Commons-beanutil中包括大量和JavaBean操作有關的工具方法,使用它能夠輕松利用Java反射機制來完畢代碼中所須要的功能,而不須要具體研究反射的原理和使用,同一時候,該類庫中提出了動態Bean的概念,不但提供現有JavaBean的全部功能,並且還能夠在執行時動態的對Bean中的屬性數據類型進行改動以及增刪屬性。
本文研究的是v1.7版本號的commons-utils類庫。
2. 轉換器
2.1. 概述
轉換器用來將輸入數據轉換成須要的數據類型。同一時候提供統一的接口,方便客戶代碼使用和擴展。
Commons-beanutils包中。全部轉換器都從org.apache.commons.beanutils.Converter接口集成,加入自己須要的實現。
轉換器分為下面三個部分:
l 數組轉換器
l 普通轉換器
l 地區敏感的轉換器
l 轉換器工具類
Converter子類包括的都是轉換器的實現,普通情況下,不須要直接實例化這些類,僅僅須要使用ConvertUtil中convert方法,就能夠進行數據類型的轉換。
高級用戶不但能夠使用默認的轉換方式,還能夠向ConvertUtils中注冊新的或替代原有的轉換器,實現須要的業務邏輯。
2.2. 轉換器接口
轉換器接口的具體信息例如以下:
類名 |
描寫敘述 |
Converter |
BeanUtil框架中使用的類型轉換接口。能夠將輸入數據轉換成須要的類型 |
2.3. 數組轉換器
2.3.1. 概述
數組轉換器的實現被封裝在org.apache.commons.beanutils.converters包中。它的功能是將一定格式的輸入字符串轉換成不同類型的數組。輸入數據以逗號分隔。開頭和結尾能夠用大括號括起來,比如:“{1, 2, 3, 4, 5}”。
全部數組轉換器實現都從一個名為AbstractArrayConverter的抽象基類中集成,這個類提供了解析輸入字符串的工具方法。
2.3.2. 類說明
數組轉換器的具體類說明例如以下:
類名 |
描寫敘述 |
AbstractArrayConverter |
用來將輸入字符串轉換成數組的抽象類,提供了全部ArrayConverter須要的公共方法。 |
BooleanArrayConverter |
將輸入的不論什么對象轉換成boolean數組,傳入對象要滿足下面幾個條件后才干正確轉換: 1. 傳入對象為boolean數組,直接返回。 2. 傳入對象為String數組。僅僅要數組中的每一個元素滿足特定條件,就能夠正常解析為boolean數組。 3. 傳入對象為其它類型,僅僅要對象的toString()方法返回的字符串為逗號分隔的格式,而且每部分滿足特定條件,就能夠解析為boolean數組。 能夠向boolean類型轉換的字符串例如以下: l yes。y。true,on,1被轉換為true l no。n。false,off。0被轉換成false l 其它字符串為非法字符串,假設遇到就停止轉換,拋出異常或返回默認值。
原有代碼實現的缺陷和改進方案: 1. 字符串數組解析算法反復:能夠通過提取公共函數的方法消除反復。
2. try/catch嵌套混亂:解決方法同上,僅僅要提取公共方法后自然就能夠解決問題。 3. 特殊字符串被硬編碼,比如yes。y。no,n等:將這些特殊字串提取成常量。放入映射表中維護,降低復雜的推斷語句。 |
ByteArrayConverter |
將傳入對象轉換為byte數組,假設轉換失敗,就拋出異常。
仍然有反復代碼的問題。
|
CharacterArrayConverter |
將對象轉換為char數組 |
DoubleArrayConverter |
將對象轉換成double數組 |
FloatArrayConverter |
將對象轉換成float數組 |
IntegerArrayConverter |
將對象轉換成int數組 |
LongArrayConverter |
將對象轉換成long數組 |
ShortArrayConverter |
將對象轉換成short數組 |
StringArrayConverter |
javadoc中說是將String數組轉換成String數組。但不知道這樣有什么意義。 查看代碼后發現算法僅僅能轉換int型的數組為String數組。其它的類型比方long型數組均不能正常轉換。 最好不用這個類。 |
2.3.3. 類圖
2.3.4. 小結
通過閱讀數組轉換器的代碼,發現代碼存在下面問題:
1. 代碼冗余:代碼不夠簡潔,每一個類中都或多或少的存在代碼復制粘貼的痕跡。
2. 部分類的類型轉換時存在缺陷,不能正常轉換。
2.4. 普通轉換器
2.4.1. 概述
普通轉換器提供了將字符串轉換成Java中的數字、時間日期類型和其它類型對象的方法。
普通轉換器都直接從Converter接口集成,實現當中的抽象方法。
用戶不但能夠直接使用這些工具方法。也能夠自己實現一些特殊業務需求的轉換器。僅僅要實現Converter接口就可以。
2.4.2. 類說明
普通轉換器的類說明例如以下:
類名 |
描寫敘述 |
BigDecimalConverter |
將字符串轉換成BigDecimal類型數據。 轉換失敗時能夠拋出異常,也能夠返回默認值。 |
BigIntegerConverter |
將數組轉換成java.math.BigInteger類型對象,假設轉換失敗,能夠拋出異常,也能夠直接返回默認值。
|
BooleanConverter |
將字符串轉換成boolean類型對象。 假設轉換失敗,能夠拋出異常。也能夠返回默認值。 |
ByteConverter |
將字符串轉換成byte類型,假設轉換失敗。拋出異常或返回默認值。 |
CharacterConverter |
將字符串轉換成char,假設轉換失敗。拋出異常或返回默認值。 |
ClassConverter |
從當前上下文的ClassLoader中載入類。假設類不存在。能夠拋出異常,也能夠直接返回默認值。
|
DoubleConverter |
將輸入字符串轉換成double類型。假設轉換失敗,能夠拋出異常。也能夠返回默認值。 |
FileConverter |
依據輸入字符串初始化File對象,假設對象創建失敗,拋出異常或返回默認值。 |
FloatConverter |
將字符串轉換成Float類型。假設轉換失敗,能夠拋出異常,能夠返回默認值。
|
IntegerConverter |
將字符串轉換成Integer類型對象。假設轉換失敗。能夠拋出異常。也能夠返回默認值。 |
LongConverter |
將字符串轉換成Long類型對象,假設轉換失敗,能夠拋出異常,也能夠返回默認值。 |
ShortConverter |
將字符串轉換成short類型對象,假設轉換失敗,能夠拋出異常,也能夠返回默認值。
|
SqlTimeConverter |
將字符串轉換成java.sql.Time對象,假設轉換失敗。能夠拋出異常,也能夠返回默認值。 |
SqlTimestampConverter |
將字符串轉換成javax.sql.Timestamp對象,假設轉換失敗,能夠拋出異常。也能夠返回默認值。
|
StringConverter |
將字符串對象轉換成字符串對象。 單獨使用沒有什么意義,可是在面向接口編程中實現了一種通用的轉換方法。比較實用。
|
URLConverter |
將字符串轉換成URL對象。假設轉換失敗,拋出異常,或者直接返回默認值。
|
|
|
2.4.3. 類圖
通用轉換器的類結構圖例如以下:
2.4.4. 小結
通用轉換器存在的問題是:
對於默認值的校驗不到位。沒有針對詳細Converter的類型進行校驗,一旦轉換失敗,直接返回默認值后可能導致興許代碼出現ClassCastException。沒有從源頭杜絕這樣的情況發生,盡管這樣設計更加靈活,但弊大於利,最好是在類創建時進行校驗。
2.5. 地區敏感轉換器
2.5.1. 概述
地區敏感轉換器都被封裝在org.apache.commons.beanutils.locale和org.apache.commons.beanutils.locale.converters包中,前者提供一個集成自Converter的通用接口。后者提供這個接口的詳細實現。
地區敏感轉換器主要實現了當須要分地區進行轉換時,須要進行的操作。主要功能是將帶有不同地區特征的字符串轉換成數字和時間日期類型對象。
2.5.2. 類說明
地區敏感轉換器的類說明例如以下:
類名 |
描寫敘述 |
LocaleConverter |
進行地區敏感的數據類型的轉換 |
BaseLocaleConverter |
封裝全部地區敏感conveter的公共方法 |
DateLocaleConverter |
將地區敏感對象轉換成java.util.Date對象。
|
SqlDateLocaleConverter |
將輸入對象轉換成java.sql.Date 對象 |
SqlTimeLocaleConverter |
將輸入對象轉換成java.sql.Time對象 |
SqlTimestampLocaleConverter |
將輸入對象轉換成java.sql.Timestamp的格式 |
DecimalLocaleConverter |
將地區敏感的輸入轉換成java.lang.Decimal對象 |
BigDecimalLocaleConverter |
將輸入的地區敏感字符串轉換成java.math.BigDecimal對象。 沒有重寫不論什么方法。應該僅僅是為了和其它實現樣式一致編寫的方法。 |
BigIntegerLocaleConverter |
將輸入的地區敏感的對象轉換成java.math.BigInteger 對象 沒有重寫不論什么方法,應該僅僅是為了和其它實現樣式一致編寫的方法。 |
ByteLocaleConverter |
將輸入的地區敏感的字符串轉換成java.lang.Byte 對象 |
DoubleLocaleConverter |
將地區敏感的對象轉換成java.lang.Double對象 |
FloatLocaleConverter |
將地區敏感的字符串轉換成java.lang.Float對象 |
IntegerLocaleConverter |
將地區敏感的字符串轉換成java.lang.Integer對象 |
LongLocaleConverter |
將地區敏感的字符串轉換成java.lang.Long對象 |
ShortLocaleConverter |
將地區敏感的字符串轉換成java.lang.Short對象 |
StringLocaleConverter |
將字符串轉換成數字的字符串形式。
好像沒有什么實際的作用 |
2.5.3. 類圖
地區敏感轉換器的類圖例如以下:
2.5.4. 小結
地區敏感轉換器中全部參數參數都是直接從構造函數中輸入的,沒有get和set,代碼冗余度非常大,須要重構。
2.6. 轉換器工具類
轉換器相關的工具類是外界實際使用的接口。默認情況下,系統會向工具類中注冊上述各種類型數據的轉換器對象,用戶能夠自己定義這些注冊信息。加入。改動或刪除自己不須要的轉換器。還能夠將自己實現的類型注冊到轉換器中。
轉換器工具類的具體信息例如以下:
類名 |
描寫敘述 |
ConvertUtils |
將字符串對象轉換成對應類型的對象。如。將String對象轉換成Integer類型的對象,或將String對象轉換成Integer數組對象。
默認使用系統自己定義的轉換器,但接口開放。能夠自己定義轉換器進行數據類型轉換。 |
ConvertUtilsBean |
實際進行數據轉換的類。
|
LocaleConvertUtils |
和ConvertUtils作用類似。在轉換的過程中依據不同的地區進行不用的轉換。適用於地區敏感的數據。 |
LocaleConvertUtilsBean |
2.7. 轉換器總結
轉換器這一套代碼中實現了字符串向Java中各種數據類型的轉換,這樣在轉換數據類型時不須要了解各種數據類型的轉換API。僅僅須要知道Converter接口就可以。方便了開發者編寫代碼。
但這套代碼也有非常多不足,當中最大的就是代碼冗余的問題,小到函數內部的實現,大到整個的類結構,或多或少的都存在代碼復制粘貼的影子,能夠通過重構讓代碼變得更加清晰。
3. 動態bean
3.1. 概述
我們知道。每個JavaBean對象中包括一個Class對象,這個對象是單實例的而且在當前類載入器中全局唯一,由JVM維護。用來存儲Bean中的屬性描寫敘述信息,這些信息在執行時無法改動。
動態bean符合JavaBean架構的基本思想,每個DynaBean實例有一個DynaClass對象。這個對象在同類DynaBean中唯一。但能夠動態的對屬性進行增刪改的操作。這樣就彌補了原來JavaBean架構中當Bean定義后不能對Bean中屬性進行擴展的缺點。同一時候,提供了對bean中屬性進行get/set的統一工具類,這些工具類的接口能夠兼容動態Bean、標准Bean,以及映射(map)。
3.2. 動態Bean屬性
動態Bean中的屬性使用DynaProperty對象進行描寫敘述,
類名 |
描寫敘述 |
DynaProperty |
動態bean中的屬性,由屬性名。屬性類型兩部分組成,對於數組、鏈表這類復雜類型,還增加了內容類型的概念,用來描寫敘述這些復雜數據接口內部對象的類型。
|
3.3. 動態Bean的Class對象
3.3.1. 概述
動態Bean的Class對象描寫敘述了Bean中包括的屬性以及屬性的數據類型,分為DynaClass和MutableDynaClass兩個接口,當中MutableDynaClass接口繼承自DynaClass接口。同一時候提供對Bean屬性進行改動的方法。
具體描寫敘述例如以下:
接口名 |
描寫敘述 |
DynaClass |
動態類模仿java.lang.Class 的實現。 使用DynaClass創建DynaBean 對象。全部DynaBean 對象共享一個DynaClass實例。 |
MutableDynaClass |
對於DynaClass的特殊擴展,同意動態的加入和移除類的屬性 |
3.3.2. 類說明
有多個類擴展了以上兩個接口,具體信息例如以下:
類名 |
描寫敘述 |
BasicDynaClass |
對DynaClass接口的基本實現。提供了最主要的功能。 |
JDBCDynaClass |
實現JDBC邏輯的動態類 |
ResultSetDynaClass |
封裝java.sql.ResultSet對象。提供和其它對象一樣訪問方式的類。
|
RowSetDynaClass |
從ResultSet中讀取全部數據,封裝在RowSetDynaBean中。
|
LazyDynaClass |
|
DynaProperty |
動態bean中的屬性 |
WrapDynaClass |
封裝標准JavaBean的動態bean的DynaClass對象 |
3.3.3. 類圖
上述類之間的關系例如以下:
3.4. 動態Bean
3.4.1. 概述
全部動態Bean實例都繼承自DynaBean接口,能夠創建DynaBean的實例,並對其屬性進行改動。
接口具體信息例如以下:
接口名 |
描寫敘述 |
DynaBean |
提供了屬性類型,名稱。內容能夠動態改動的JavaBean。
|
3.4.2. 類說明
下面類實現了DynaBean接口:
類名 |
描寫敘述 |
WrapDynaClass |
封裝標准JavaBean的動態bean的DynaClass對象 |
BasicDynaBean |
對DynaBean接口的最小實現 |
ResultSetIterator |
封裝ResultSetDynaClass的DynaBean |
LazyDynaBean |
能夠動態加入屬性的Bean |
WrapDynaBean |
封裝標准的JavaBean。提供DynaBean的訪問方式 |
ConvertingWrapDynaBean |
WrapDynaBean的子類。在set數據時能夠提供必要的數據類型轉換 |
3.4.3. 類圖
4. 工具類
4.1. 概述
和不論什么成熟的開源包一樣,commons-beanutils作為一個工具包,提供了對JavaBean以及動態Bean進行操作的工具類,即使沒有使用動態Bean,仍然能夠放心的使用這些工具類。
經常使用的工具類有下面幾個部分:
l PropertyUtils:對JavaBean中的屬性值進行操作。
l MethodUtils:使用反射的方式請求bean中的方法。
l ConstructorUtils:使用反射的方式構造Bean的新實例。
l BeanUtils:對JavaBean提供拷貝。賦值等操作。
l LocaleBeanUtils:和BeanUtils功能類似,但還能夠提供地區敏感數據的操作。
l ContextClassLoaderLocal:為不同線程保存須要數據的工具類。
4.2. 具體說明
工具類的具體說明例如以下:
類名 |
描寫敘述 |
ContextClassLoaderLocal |
提供保存不同線程數據的工具類,在JDK1.5中已經能夠用ThreadLocal取代. |
PropertyUtils |
使用Java反射API編寫的工具類。用於方便的進行get和set。
本工具類的全部實現都是對PropertyUtilsBean的封裝和代理。
|
PropertyUtilsBean |
使用Java反射API進行set和get的工具類。 |
MethodUtils |
封裝以放射方式請求方法的工具方法 |
ConstructorUtils |
使用反射方法請求構造函數創建新實例的工具類。能夠簡化程序中使用反射方式創建對象的代碼。 |
BeanUtilsBean |
提供對標准JavaBean和動態bean的操作。主要功能是復制bean中的內容,拷貝bean,為bean中的內容賦值和讀取bean中內容。
|
BeanUtils |
|
LocaleBeanUtils |
和BeanUtils作用類似,但在運行對應方法時能夠進行地區敏感數據的轉換。
|
LocaleBeanUtilsBean |
4.3. PropertyUtilsBean的方法
通過研讀commons-beanutils的源碼,整理了PropertyUtilsBean中的相關方法,例如以下所看到的:
PropertyUtilsBean的方法名 |
描寫敘述 |
copyProperties |
bean屬性拷貝(copyProperties)。能夠拷貝bean中全部屬性,拷貝時遵循原來bean中的訪問控制策略: l 動態bean向動態bean拷貝 l 動態bean向標准bean拷貝 l MAP向動態bean拷貝 l Map向標准bean拷貝 l 標准bean向動態bean拷貝 l 標准bean向標准bean拷貝 |
describe |
將bean屬性復制到Map中。
僅僅拷貝源bean中可讀的屬性,忽略其它屬性。 |
getIndexedProperty |
得到bean中的索引屬性值: 有兩種形式,一種的參數是string。還有一種的參數是屬性名和位置。前者是“name[1]”的形式,后者是“name, 1”的形式。 比如。要取出bean中名為name屬性的第2個對象,能夠使用getIndexedProperty(bean, “name[1]”)的形式。也能夠使用getIndexedProperty(bean, “name”, 1)的形式。 l 假設輸入是動態bean。能夠得到動態bean的索引屬性。
假設屬性是數組或列表,能夠得到對應屬性。 |
getMappedProperty |
得到bean中的映射屬性值: 本方法有兩種原型。能夠輸入(bean, “name(key)”)取出bean中名為name映射屬性中以key為鍵的屬性值。也能夠輸入(bean, “name”, “key”)的方式取出bean中名為name映射屬性中以key為鍵的屬性值。
|
getNestedProperty |
得到bean中的嵌套屬性值。獲取值的bean須要有get方法,還要有public訪問權限,否則BeanUtils中的類無法訪問。 適合在web頁面上進行bean值的讀取。 |
getPropertyDescriptor |
得到bean中對應屬性的屬性描寫敘述符 |
getPropertyDescriptors |
得到bean中全部屬性的屬性描寫敘述符 |
getPropertyEditorClass |
得到bean中的屬性編輯器類 |
getPropertyType |
得到bean中對應屬性類型 |
getReadMethod |
得到屬性描寫敘述符中的get方法 |
getSimpleProperty |
得到bean中簡單屬性的值 |
getWriteMethod |
得到屬性描寫敘述符中的寫方法 |
isReadable |
推斷bean中的指定屬性是否可讀 |
isWriteable |
推斷bean中的相應方法是否可寫 |
setIndexedProperty |
向bean中的索引屬性賦值 |
setMappedProperty |
向bean中的映射屬性賦值 |
setNestedProperty |
向bean中的內嵌屬性賦值 |
setProperty |
為bean中的屬性賦值(包含簡單屬性和索引屬性) |
setSimpleProperty |
為bean中的簡單屬性賦值 |
5. 總結
Commons-beanutils是一款優秀的工具類庫。不但提供了一種能夠動態擴展屬性的JavaBean,同一時候封裝了Java的反射機制。使用者能夠更加easy的對反射進行操作,而不須要了解那么多和反射相關的知識。
轉自:https://blog.csdn.net/weixin_34038652/article/details/85894505