国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

(spring-第13回【IoC基礎篇】)PropertyEditor(屬性編輯器)--實例化Bean的第五大利器

2019-11-14 14:57:50
字體:
來源:轉載
供稿:網友

上一篇講到javaBeans的屬性編輯器,編寫自己的屬性編輯器,需要繼承PRopertyEditorSupport,編寫自己的BeanInfo,需要繼承SimpleBeanInfo,然后在BeanInfo中把特定的屬性編輯器和需要編輯的屬性綁定起來(詳情請查看上一篇)。

Spring的屬性編輯器僅負責將配置文件中的字面值轉換成Bean屬性的對應值。(而JavaBean的屬性編輯器能夠通過界面來手動設置bean屬性的值)。如果屬性的類型不同,轉換的方法就不同。正如javabean的屬性編輯器一樣,特定類型的屬性對應著特定的屬性編輯器。Spring在PropertyEditorSupport中提供了默認的屬性編輯器。PropertyEditorSupport中有兩個重要的變量:defaultEditors、customEditors,它們分別存放默認的屬性編輯器和用戶自定義的屬性編輯器。 下面是PropertyEditorSupport的部分源碼

 1 private void createDefaultEditors() { 2         this.defaultEditors = new HashMap<Class, PropertyEditor>(64); 3  4         // Simple editors, without parameterization capabilities. 5         // The JDK does not contain a default editor for any of these target types. 6         this.defaultEditors.put(Charset.class, new CharsetEditor()); 7         this.defaultEditors.put(Class.class, new ClassEditor()); 8         this.defaultEditors.put(Class[].class, new ClassArrayEditor()); 9         this.defaultEditors.put(Currency.class, new CurrencyEditor());10         this.defaultEditors.put(File.class, new FileEditor());11         this.defaultEditors.put(InputStream.class, new InputStreamEditor());12         this.defaultEditors.put(InputSource.class, new InputSourceEditor());13         this.defaultEditors.put(Locale.class, new LocaleEditor());14         this.defaultEditors.put(Pattern.class, new PatternEditor());15         this.defaultEditors.put(Properties.class, new PropertiesEditor());16         this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());17         this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());18         this.defaultEditors.put(URI.class, new URIEditor());19         this.defaultEditors.put(URL.class, new URLEditor());20         this.defaultEditors.put(UUID.class, new UUIDEditor());21 22         // Default instances of collection editors.23         // Can be overridden by registering custom instances of those as custom editors.24         this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));25         this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));26         this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));27         this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));28         this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));29 30         // Default editors for primitive arrays.31         this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());32         this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());33 34         // The JDK does not contain a default editor for char!35         this.defaultEditors.put(char.class, new CharacterEditor(false));36         this.defaultEditors.put(Character.class, new CharacterEditor(true));37 38         // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.39         this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));40         this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));41 42         // The JDK does not contain default editors for number wrapper types!43         // Override JDK primitive number editors with our own CustomNumberEditor.44         this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));45         this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));46         this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));47         this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));48         this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));49         this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));50         this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));51         this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));52         this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));53         this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));54         this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));55         this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));56         this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));57         this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));58 59         // Only register config value editors if explicitly requested.60         if (this.configValueEditorsActive) {61             StringArrayPropertyEditor sae = new StringArrayPropertyEditor();62             this.defaultEditors.put(String[].class, sae);63             this.defaultEditors.put(short[].class, sae);64             this.defaultEditors.put(int[].class, sae);65             this.defaultEditors.put(long[].class, sae);66         }67     }

可以看到,defaultEditors、customEditors是哈希Map類型的,以屬性的類為鍵,以對應屬性編輯器的對象為值。

以48行為例,我們看一下CustomNumberEditor是個什么鬼,下面是源碼:

 1 public class CustomNumberEditor extends PropertyEditorSupport { 2  3     private final Class numberClass; 4  5     private final NumberFormat numberFormat; 6  7     private final boolean allowEmpty; 8  9 10     public CustomNumberEditor(Class numberClass, boolean allowEmpty) throws IllegalArgumentException {11         this(numberClass, null, allowEmpty);12     }13 14     15     public CustomNumberEditor(Class numberClass, NumberFormat numberFormat, boolean allowEmpty)16         throws IllegalArgumentException {17 18         if (numberClass == null || !Number.class.isAssignableFrom(numberClass)) {19             throw new IllegalArgumentException("Property class must be a subclass of Number");20         }21         this.numberClass = numberClass;22         this.numberFormat = numberFormat;23         this.allowEmpty = allowEmpty;24     }25 26 27     /**28      * Parse the Number from the given text, using the specified NumberFormat.29      */30     @Override31     @SuppressWarnings("unchecked")32     public void setAsText(String text) throws IllegalArgumentException {33         if (this.allowEmpty && !StringUtils.hasText(text)) {34             // Treat empty String as null value.35             setValue(null);36         }37         else if (this.numberFormat != null) {38             // Use given NumberFormat for parsing text.39             setValue(NumberUtils.parseNumber(text, this.numberClass, this.numberFormat));40         }41         else {42             // Use default valueOf methods for parsing text.43             setValue(NumberUtils.parseNumber(text, this.numberClass));44         }45     }46 47     /**48      * Coerce a Number value into the required target class, if necessary.49      */50     @Override51     @SuppressWarnings("unchecked")52     public void setValue(Object value) {53         if (value instanceof Number) {54             super.setValue(NumberUtils.convertNumberToTargetClass((Number) value, this.numberClass));55         }56         else {57             super.setValue(value);58         }59     }60 61     /**62      * Format the Number as String, using the specified NumberFormat.63      */64     @Override65     public String getAsText() {66         Object value = getValue();67         if (value == null) {68             return "";69         }70         if (this.numberFormat != null) {71             // Use NumberFormat for rendering value.72             return this.numberFormat.format(value);73         }74         else {75             // Use toString method for rendering value.76             return value.toString();77         }78     }79 80 }

真相大白,與上一節javabean的屬性編輯器類似,CustomNumberEditor 是spring內置的屬性編輯器,它也是繼承了PropertyEditorSupport ,并且覆蓋了setAsText、setValue、getAsText方法。所以,這是擴展javabean的屬性編輯器的通用方法。那么我們編寫自己的屬性編輯器也應該這樣做。(javabean的屬性編輯器相關內容請查看上一節)。而且結合上一節我們知道在這里,getAsText表示把<bean>標簽里的屬性值拿到,而setAsText表示把拿到的標簽字面值轉換成bean屬性的有變量類型的值。比如,下面是Car的xml屬性配置:

1 <bean id="car" class="com.mesopotamia.test1.Car" 2             p:name="汽車"3          p:brand="寶馬"4          p:maxSpeed="200"/>

下面是Car的Bean類:

1 public class Car {2     private String name;3     private String brand;4     private double maxSpeed;

在XML屬性配置中是沒有類型之分的,經過屬性編輯器的轉換,就可以給Car的對應屬性賦予對應的值。

spring提供的默認屬性編輯器支持的類型是有限的,如果要自定義屬性編輯器,就要擴展PropertyEditorSupport ,并且把自己的屬性編輯器注冊到spring容器中。下面我們一起來設計一個自定義的屬性編輯器并把它注冊到spring容器中使用。

 

現在有一個Car類:

 1 public class Car { 2     private String name; 3     private String brand; 4     private double maxSpeed; 5 。。。 6 省略getter、setter方法 7  8 public String toString(){ 9         return "名字:"+name+" 型號:"+brand+" 速度:"+maxSpeed;10     }

有一個Store類,這個Store類擁有一個Car類型的屬性:

1 public class Store {2     3     private Car car;4 5 。。。省略getter、setter方法。6 7 public String toString(){8         return car.toString();9     }

下面是配置文件:

 1 <bean id="car" class="com.mesopotamia.test1.Car"  2             p:name="汽車" 3          p:brand="寶馬" 4          p:maxSpeed="200"/> 5           6    <bean id="store" class="com.mesopotamia.test1.Store"> 7            <property name="car"> 8                <ref bean="car"/> 9            </property>10    </bean>

這是典型的bean引用方式。那么,當我加載spring容器,調用Store類的對象,該Store的car屬性就自動擁有了name、brand、maxSpeed值了。下面是Main:

1 public static void main(String args[]){2         applicationContext ctx = new ClassPathXmlApplicationContext("com/mesopotamia/test1/*.xml");3         //Car car1 = ctx.getBean("car1",Car.class);4         Store store=ctx.getBean("store",Store.class);5         log.info(store.toString());6     }

運行結果:

1 2015-11-29 23:21:24,446  INFO [main] (Car.java:22) - 調用了Car的構造函數,實例化了Car..2 2015-11-29 23:21:24,493  INFO [main] (Store.java:13) - 調用了Store的構造函數,實例化了Store。。。3 2015-11-29 23:21:24,505  INFO [main] (Main.java:16) - 名字:汽車 型號:寶馬 速度:200.0

第1、2行的打印語句我分別寫在Car、Store的構造函數里,所以,一經實例化必須打印。而第3行,我打印的是store 的toString()方法,而該方法又調用的是Car的toString()方法,然后打印出了Car的屬性值。

 

完美。然而,我們現在不這樣干,換個玩兒法,我把配置文件改為如下的方式:

1  <bean id="car" class="com.mesopotamia.test1.Car"/>2          3    <bean id="store" class="com.mesopotamia.test1.Store">4            <property name="car" value="汽車,寶馬,200.00"/>5    </bean>

規則變了,我要求在實例化Store后,把汽車,寶馬,200.00分別賦值給Store的Car屬性的對應變量。

而屬性編輯器就是為了把這個字面值轉換成具體屬性的值的,因此,需要使用屬性編輯器。

而本例中這種轉換方式spring的默認屬性編輯器并不支持,所以,我們要自定義屬性編輯器。

自定義屬性編輯器,首先,繼承PropertyEditorSupport ,然后,覆蓋setAsText()、getAsText()方法。

由于我們不需要跟javabean一樣,用getAsText()獲取屬性值然后放到下拉框中,在當前屬性編輯器中也不需要獲取它,

所以,我們只需要覆蓋setAsText()方法。代碼如下:

 1 public class CustomCarEditor extends PropertyEditorSupport { 2     public void setAsText(String text){ 3         if(text == null || text.indexOf(",") == -1){ 4             throw new IllegalArgumentException("設置的字符串格式不正確"); 5         } 6         String[] infos = text.split(","); 7         Car car = new Car(); 8         car.setName(infos[0]); 9         car.setBrand(infos[1]);10         car.setMaxSpeed(Double.parseDouble(infos[2]));11         setValue(car);12     }

取出文本值,分割逗號,新建Car對象,設置屬性值,最后調用父類的setValue方法給Store的Car屬性賦值。

那么setValue如何知道把括號里的對象參數賦予給誰呢?我們注冊該屬性編輯器時就會知道。

自定義的屬性編輯器寫好了,接下來要注冊到spring容器中,注冊方法如下:

 1  <bean id="store" class="com.mesopotamia.test1.Store"> 2            <property name="car" value="汽車,寶馬,200.00"/> 3    </bean> 4     5    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> 6         <property name="customEditors"> 7             <map> 8                 <entry key="com.mesopotamia.test1.Car"> 9                     <bean class="com.mesopotamia.test1.CustomCarEditor" />10                 </entry>11             </map>12         </property>13     </bean>

實際上是注冊加載了CustomEditorConfigurer,這個類是專門負責注冊自定義屬性編輯器的。我們一開始講到,PropertyEditorSupport里面有個變量叫customEditors,用來存放自定義屬性編輯器,它是一個HashMap類型,其中Key是屬性類,Value是屬性對應的屬性編輯器。而上面配置文件中的6-9行恰好是customEditors變量以及存放的map。CustomEditorConfigurer就負責把6-9行轉換成哈希Map交給PropertyEditorSupport。

當BeanWrapper在設置store的car屬性時(BeanWrapper負責在實例化后期設置屬性值),它會檢索自定義屬性編輯器的注冊表,然后發現Car屬性類型對應著CustomCarEditor,它就會去尋找這個屬性編輯器進行后續操作。

 

自定義屬性編輯器步驟總結:

  1. 繼承PropertyEditorSupport類,覆蓋setAsText方法;
  2. 注冊自定義的屬性編輯器。

 

CustomEditorConfigurer是BeanFactoryPostProcessor的實現類,因此它也是一個工廠后處理器。所謂的工廠后處理器,就是在實例化bean的過程中對bean進行處理,工廠模式本身就是把用戶要使用的bean在內部實例化好了,當外部調用的時候直接吐出一個現成的對象來,所以,屬性編輯屬于工廠后處理器的任務。

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 同仁县| 舒城县| 新宁县| 中西区| 呼伦贝尔市| 太和县| 胶南市| 怀来县| 奉节县| 丹东市| 会宁县| 孝昌县| 江永县| 泸西县| 林甸县| 和龙市| 洛宁县| 德昌县| 阿坝县| 天峻县| 田阳县| 随州市| 钟山县| 安图县| 方城县| 喀喇沁旗| 顺义区| 洪湖市| 乌鲁木齐市| 莱西市| 墨玉县| 尚义县| 灵丘县| 涟源市| 原阳县| 江西省| 怀安县| 垫江县| 内丘县| 林芝县| 高碑店市|