在 Spring 配罝文件中,用戶不但可以將 String、int 等字面值注入 Bean 中,還可以將集合、Map 等類型的數據注入 Bean 中,此外還可以注入配置文件中其他定義的 Bean。
1.字面值
所謂 "字面值" 一般是指可用字符串表示的值,這些值可以通過 <value> 元素標簽進行注入,在默認情況下,基本數據類型及其封裝類、String 等類型都可以采取字面值注入的方式。Spring 容器在內部為字面值提供了編輯器。它可以將以字符串表示的字面值轉換為內部變量的相應類型。Spring 允許用戶注冊自定義的編輯器,以處理其他類型屬性注入時的轉換工作。
在下面的示例中,我們為 Car 注入了兩個屬性值,並在 Spring 配罝文件中使用字面值提供配置值,如下所示。
字面值注入字面值
<bean id="car" class="com.smart.attr.Car" lazy-init="default"> <property name="brand"> <value><![CDATA[紅旗&CA72]]></value> </property> <property name="maxSpeed">① <value>200</value> </property> <property name="price" value="2000.00" /> </bean>
由於①處的 brand 屬性值包含一個 XML 的特殊符號,因此我們特意在屬性值外添加了一個XML特殊標簽 <![CDATA[]]>。<![CDATA[]]> 的作用是讓 XML 解析器將標簽中的字符串當作普通的文本對待,以防止特殊字符串對 XML 格式造成破壞。
XML中共有5個特殊的字符,分別是 &、<、>、“、' 。如果配置文件中的注入值包括這些特殊字符,就需要進行特別處理。有兩種解決方法:其一,采用本例中的 <![CDATA[]]> 特殊標簽,將包含特殊字符的字符串封裝起來;其二,使用 XML 轉義序列表示這些特殊字符,這5個特殊字符所對應的XML轉義序列特殊符號
特殊符號 轉義序列
< <
> >
& &
“ "
' '
如果使用XML轉義序列,則可以使用以下配置替換上面代碼的配置。
<property name="brand"> <value>紅旗&CA72</va1ue> </property>
注意:一般情況下,XML 解析器會忽略元素標簽內部字符串的前后空格,但 Spring 卻不會忽略元素標簽內部字符串的前后空格如通過以下配置為 brand 屬性提供注入值:
<property name="brand"><value> 紅旗CT72 </value></property>
那么 Spring 會將 "紅旗CT72" 連同其前后空格一起賦給 brand 屬性
2.引用其他 Bean
Spring IOC 容器中定義的 Bean 可以相互引用,IOC 容器則充當 "紅娘" 的角色。下面創建一個新的 Boss 類,Boss 類中擁有一個 car 類型的屬性。
public class Boss { private Car car; //①設置 car 屬性 public void setCar(Car car) { this.car = car; } ... }
boss 的 Bean 通過 <ref> 元素引用 car Bean,建立起 boss 對 car 的依賴。
<bean id="car" class="com.smart.attr.Car"/> <bean id="boss" class="com.smart.attr.Boss"> <property name="car"> <ref bean="car" /> </property> </bean>
<ref> 元素可以通過以下3個屬性引用容器中的其他Bean
1、bean:通過該屬性可以引用同一容器或父容器中的 Bean,這是最常見的形式。
2、local:通過該屬性只能引用同一配置文件中定義的 Bean,它可以利用 XML 解析器自動檢驗引用的合法性,以便開發人員在編寫配置時能夠及時發現並糾正配置錯誤。
3、parent:引用父容器中的Bean,如 <ref parent="car"> 的配置說明 car 的 Bean 是父容器中的 Bean。
為了說明子容器對父容器中 Bean 的引用,我們來看一個具體的例子。假設有兩個配置文件 beans1.xml 和 beans2.xml,其中 beans1.xml 被父容器加載,其配置內容如下:
<bean id="car" class="com.smart.attr.Car"> <property name="brand" value="紅旗CA72" /> <property name="maxSpeed" value="200" /> <property name="price" value="2000.00" /> </bean>
而 beans2.xml 被子容器加載,其配置內容如下:
<bean id="car" class="com.smart.attr.Car"> <property name="brand" value="吉利CT5" /> <property name="maxSpeed" value="100" /> <property name="price" value="1000.00" /> </bean> <bean id="boss" class="com.smart.attr.Boss"> <property name="car"> <ref parent="car" /> </property> </bean>
在 beans1.xml 中配置了一個 car Bean,在bean2.xml中也配置了一個 car Bean。分別通過父、子容器加載 beans1.xml 和 beans2.xml,beans2.xml 中的 boss 通過<ref parent="car">引用父容器中的car。
下面是分別使用父、子容器加載 beans1.xml 和 beans2.xml 配置文件的代碼:
//①父容器 ClassPathXmlApplicationContext pFactory = new ClassPathXmlApplicationContext(new String[]{"com/smart/attr/beans1.xml"}); //②指定 pFactory 為該容器的父容器 ApplicationContext factory = new ClassPathXmlApplicationContext(new String[]{"com/smart/attr/beans2.xml"},pFactory); Boss boss = (Boss)factory.getBean("boss"); assertNotNull(boss); System.out.println(boss.getCar().toString());
運行這段代碼,在控制台中打印出以下信息:
brand:紅旗CA72/maxSpeed:200/price:2000.0
3.內部Bean
如果 car Bean 只被 boss Bean引用,而不被容器中任何其他的 Bean 引用,則可以將 car 以內部 Bean 的方式注入 Boss 中。
<bean id="boss" class="com.smart.attr.Boss"> <property name="car"> <bean class="com.smart.attr.Car"> <property name="maxSpeed" value="200"/> <property name="price" value="2000,00"/> </bean> </property> </bean>
內部 Bean 和 Java 的匿名內部類相似,既沒有名字,也不能被其他 Bean 引用,只能在聲明處為外部 Bean 提供實例注入。
內部 Bean 即使提供了 id、name、scope 屬性,也會被忽略。
4.null 值
如果用戶嘗試通過以下配置方式為 car 的 brand 屬性注入一個 null 值,那么將會得到一個失望的結果。
<bean id="car" class="com.smart.attr.Car"> <property name="brand"><value></value></property> </bean>
Spring 會將 <value></value> 解析為空字符串。那么,如何為屬性設置一個 null 的注入值呢?答案是必須使用專用的 <null/> 元素標簽,通過它可以為 Bean 的字符串或其他
對象類型的屬性注入 null 值。
<property name="brand"><null/></property>
上面的配置代碼等同於調用 car.setBrand(null) 方法。
5.級聯屬性
和 Struts、Hibernate 等框架一樣,Spring 支持級聯屬性的配置。假設我們希望在定義 Boss 時直接為 car 的屬性提供注入值,則可以采取以下配置方式:
<bean id="boss3" class="com.smart.attr.Boss"> <!-- 以圓點(.)的方式定義級別屬性--> <property name="car.brand" value="吉利CT50"/> </bean>
按照上面的配置,Sping 將調用 Boss.getCar().setBrand("吉利CT50")方法進行屬性的注入操作。這時必須對 Boss 類進行改造,為 car 屬性聲明一個初始化對象。
public class Boss { //聲明初始化對象 private Car car = new Car(); public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } ... }
在①處為 Boss 的 car 屬性提供了一個非空的 Car 實例。如果沒有為 car 屬性提供 Car 對象,那么 Spring 在設置級聯屬性時將拋出 NullValueInNestedPathExcepüon 異常。
Spring 沒有對級聯屬性的層級數進行限制,只要配置的 Bean 擁有對應於級聯屬性的類結構,就可以配置任意層級的級聯屬性,如以下定義了具有三級結構的級聯屬性。
<property name="car.wheel.brand" value="雙星"/>
6.集合類型屬性
java.util 包中的集合類型是最常用的數據結構類型,主要包括 List、set、Map、Properties,Spring 為這些集合類型屬性提供了專屬的配置標簽。
1)List
為 Boss 添加一個 List 類型的 favorites 屬性,如下:
public class Boss { private List favorites = new ArrayList(); public List getFavorites() { return favorites; } public void setFavorites(List favorites) { this.favorites = favorites; } }
對應 Spring 中的配置片段如下:
<bean id="boss1" class="com.smart.attr.Boss"> <property name="favorites"> <list> <value>看報</value> <value>賽車</value> <value>高爾夫</value> </list> </property> </bean>
List 屬性既可以通過 <value> 注入字符串,也可以通過 <ref> 注入容器中其他的Bean。
注意:假設一個屬性類型可以通過字符串字面值進行配置,那么該類型對應的數組類型的屬性(如String[]、int[] 等)也可以采用 <list> 方式進行配置。
2)Set
如果 Boss 的 favorites 屬性是 java.util.set,則采用如下配置方式:
<bean id="boss1" class="com.smart.attr.Boss"> <property name="favorites"> <set> <value>看報</value> <value>賽車</value> <value>高爾夫</value> </set> </property> </bean>
3)Map
下面為 Boss 添加一個 Map 類型的 jobs 屬性:
public class Boss { ... private Map jobs = new HashMap(); public Map getJobs() { return jobs; } public void setJobs(Map jobs) { this.jobs = jobs; } ... }
在配置文件中可以通過以下方式為 jobs 屬性提供配置值:
<bean id="boss1" class="com.smart.attr.Boss"> <property name="jobs"> <map> <entry > <key><value>AM</value></key> <value>會見客戶</value> </entry> <entry> <key><value>PM</value></key> <value>公司內部會議</value> </entry> </map> </property> <bean>
假如某一 Map 元素的鍵和值都是對象,則可以采取以下配置方式:
<entry> <key><ref bean="keyBean"/></key> <ref bean="vaIueBean"/> </entry>
4)Properties
Properties 類型其實可以看作 Map 類型的特例。Map 元素的鍵和值可以是任何類型的對象,而 Properties 屬性的鍵和值都只能是字符串。下面為 Boss 添加一個 Properties 類型的 mails 屬性:
public class Boss { ... private Properties mails = new Properties(); public Properties getMails() { return mails; } public void setMails(Properties mails) { this.mails = mails; } ... }
下面的配置片段為 mails 提供了配置:
<bean id="boss1" class="com.smart.attr.Boss"> <property name="mails"> <props> <prop key="jobMail">john-office@smart.com</prop> <prop key="lifeMail">john-life@smart.com</prop> </props> </property> </bean>
因為 Properties 鍵值對只能是字符串,因此其配置比 Map 的配置要簡單一些,注意值的配置沒有 <value> 子元素標簽。
5)強類型集合
Java5.0 提供了強類型集合的新功能,允許為集合元素指定類型。如下面 Boss 類中的 jobTime 屬性就采用了強類型的 Map 類型,元素的鍵為 String 類型,而值為 Integer類型。
public class Boss { ... private Map<String, Integer> jobTime = new HashMap<String, Integer>(); public Map<String, Integer> getJobTime() { return jobTime; } public void setJobTime(Map<String, Integer> jobTime) { this.jobTime = jobTime; } ... }
在 Spring 中的配置和非強類型集合相同
<bean id="boss1" class="com.smart.attr.Boss"> <property name="jobTime"> <map> <entry> <key><value>會見客戶</value></key> <value>124</value>//① </entry> </map> </property> </bean>
但 Spring 容器在注入強類型集合時會判斷元素的類型,將設置值轉換為對應的數據類型。如①處的設置項 124 將被轉換為 Integer 類型。
6)集合合並
Spring支持集合合並的功能,允許子 <bean> 繼承父 <bean> 的同名屬性集合元素,並將子 <bean> 中配置的集合屬性值和父 <bean> 中配置的同名屬性值合並起來作為最終 Bean 的屬性值,如下
<bean id="parentBoss" abstract="true" class="com.smart.attr.Boss"> <property name="favorites"> <!--①父<Bean> --> <set> <value>看報</value> <value>賽車</value> <value>高爾夫</value> </set> </property> </bean> <bean id="childBoss" parent="parentBoss"> <!--②指定父<Bean> --> <property name="favorites"> <set merge="true"> <!--③和父<Bean>中同名集合屬性合並 --> <value>爬山</value> <value>游泳</value> </set> </property> </bean>
③處通過 merge="true" 屬性指示子 <bean> 和父 <bean> 中的同名屬性值進行合並,即子 Bean 的 favorites 集合最終將擁有5個元素。如果設置為 merge="false",則不會和父 <bean> 中的同名集合屬性進行合並,即子 Bean 的 favorites 屬性集合只有兩個元素
7)通過 util 命名空間配置集合類型的 Bean
如果希望配置一個集合類型的 Bean,而非一個集合類型的屬性,則可以通過 util 命名空間進行配置。首先需要在 Spring 配置文件頭中引入命名空間的聲明。
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> ... </beans>
其次配置一個List類型的Bean,可以通過list-class顯式指定List的實現類。
<util:list id="favoriteList1" list-class="java.util.LinkedList"> <value>看報</value> <value>賽車</value> <value>高爾夫</value> </util:list>
再次配置一個 Set 類型的 Bean,可以通過 set-class 指定 Set 的實現類。
<util:set id="favoriteSet1" > <value>看報</value> <value>賽車</value> <value>高爾夫</value> </util:set>
最后配置一個 Map 類型的Bean,可以通過 map-class 指定 set 的實現類。
<util:map id="emails1" > <entry key="AM" value="會見客戶" /> <entry key="PM" value="公司內部會議" /> </util:map>
此外,<util:list> 和 <util:set> 支持 value-type 屬性,指定集合中的值類型;而 <util:map> 支持 key-type 和 value-type 屬性,指定 Map 的鍵和值類型。
