1. 程式人生 > >BeanUtils的copyProperties,populate實現方式分析以及容易引發的Bug

BeanUtils的copyProperties,populate實現方式分析以及容易引發的Bug

BeanUtils的copyProperties方法用來將orig中的成員變數的值複製給dest,即將已經存在的dest變為orig的副本。

public void copyProperties(Object dest, Object orig) { 
....... 
}
 

BeanUtils的populate方法用來將Map<Key,value>中的以值(String或String[])轉換到目標bean對應的屬性中,Map中的Key是目標bean的屬性名。

public static void populate(Object bean, Map properties){ 
…… 
}

copyProperties同樣支援了populate中的功能(注apache的javadoc中,明確指明這個方法是為解析http請求引數特別定義和使用的,在正常的使用中不推薦使用.他們推薦使用BeanUtils.copyProperties方法)。

BeanUtils.copyProperties和populate的實現方法是將源bean(也可以是Map)中的每個element在轉換器(Converter)的幫助下,將轉換的結果設定到目標bean對應的屬性中。例如在HTTP 應用中需要從http request中抽取資料,http request傳遞過來的都是String 或是String陣列型別的變數而目標型別可能是各種各樣的,例如http request會有一個name=visitDate,value=’2009-05-13′的引數,而目標bean 的visitDate屬性的型別是java.util.Date。 
      BeanUtils的copyProperties和populate需要在轉換器(converter)的配合下實現源和目標物件之間的資料型別的轉換。在BeanUtils.copyProperties 的javadoc中說明的(Copy property values from the origin bean to the destination bean for all cases where the property names are the same—— 只要屬性名相同就可以從源bean中拷貝值到目標bean中)這句話提供到功能就是要通過轉換器才能實現的。在BeanUtils的 copyProperties和populate的使用過程中Converter是一個非常重要的概念,它提供了強大的擴充套件能力。

/****************************************************************/ 
public interface Converter { 
public Object convert(Class type, Object value); 

/****************************************************************/

convert方法的引數type是目標轉換的型別,引數value是被轉換的值,返回值就是轉換以後的結果。當有需要自定義或擴充套件的Converter 的時候可以通過註冊自定義的轉換器來實現,例如Beanutil自帶的DateConverter不支援String到java.util.Date的轉換,通過擴充套件DateConverter就可以實現支援。需要特別注意的是Converter 是註冊在classloader一級的,也就是說在一個class loader中同一時間只能有一個轉換器起作用(BeanUtils的copyProperties和populate會依據目標bean屬性的型別來決定啟用那個轉換器),我之前的專案中就有因為其他模組中在特定的時候會重新註冊了某個型別的轉換器,而新註冊的轉換器又沒有支援我所需要的轉換,從而導致在我的模組中出現NPE。 所以在使用BeanUtils.populate和copyProperties的時候要注意以下幾點:

1. 只在系統初始化的時候註冊一個轉換器,而不要在某個功能的執行過程中註冊轉換器。 
2. 轉換器要能夠支援專案各個模組的使用需求 
3. 謹慎使用或者思考一下BeanUtils.populate和copyProperties是你想要的方法嗎?

在我使用BeanUtils.populate的模組中本意是實現bean和Map的屬性拷貝並不需要型別和值的轉換。至於說為什麼會使用 BeanUtils.populate完全是被它支援Map所誤導,其實PropertyUtilsBean.copyProperties和 BeanUtils.copyProperties同樣支援Map。就我想要實現的功能而言通過 PropertyUtilsBean.copyProperties方法能更好地滿足。 PropertyUtilsBean.copyProperties方法不會有型別轉換的邏輯,所以需要程式設計師自己保證目標和源Bean屬性間的相容性,也正因為如此PropertyUtilsBean.copyProperties的執行效率更高。

參考資料

轉自 http://www.daniel-journey.com/archives/72