跟著柴毛毛學Spring(2)——Bean的配置
宣告一個Bean
在Spring中,讓Spring建立的物件叫做Bean,每一個bean都有成員函式和成員變數,如果bean的某些成員變數需要初始值,那麼在bean的配置檔案中宣告即可,否則Spring會給bean的成員們賦上預設的初始值。 如果已經有一個Person類,含有id和name兩個屬性:
class Person{ private long id; private String name; public void setId(long id){ this.id = id; } public long getId(){ return this.id; } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } }
然後我們需要建立一個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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.5.xsd"> <bean id="person" class="com.njupt.Person"></bean> </beans>
Spring的配置檔案由beans標籤開始,beans標籤下的bean標籤內即可宣告一個bean。 - id表示這個bean的名字,可以自定義,當我們需要使用這個物件時,通過這個id來獲取物件。 - class表示這個類的完整路徑。Spring通過class屬性找到這個類。 到此為止,Person類的配置已經完成。當程式啟動的時候,Spring會讀取這個配置檔案,根據class找到每個bean對應的類,並初始化它們。 當我們需要使用一個物件時,通過如下操作即可獲得:
ApplicationContext context = new ClassPathXmlApplicationContext("xml的路徑");
Person person = (Person)context.getBean(“bean的名字”)
給Bean注入初始值
在上述示例中,Spring建立了一個Person物件,由於未指定初始值,因此Spring為person物件的屬性賦上了預設值。下面我們來介紹如何讓Spring為一個物件賦上指定的初始值。 在Java中,給一個物件賦上初始值的方法有兩種: 1. 通過建構函式將初始值傳遞給物件 2. 在建立完物件後通過set函式為物件賦上初始值
Spring也採用了這兩種方式,分別叫做:構造器注入和屬性注入。
構造器注入
1.注入基本型別的值 我們首先為Person類新增一個建構函式:
class Person{
private long id;
private String name;
public Person(String name,long id){
this.name = name;
this.id = id;
}
public void setId(long id){
this.id = id;
}
public long getId(){
return this.id;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
然後在bean標籤中新增屬性:
<bean id="person" class="com.njupt.Person">
<constructor-arg value="柴毛毛"/>
<constructor-arg value="1"/>
</bean>
關於constructor-arg有如下注意點: - 屬性constructor-arg的次序需要和建構函式中引數的順序一致。 - value表示屬性值。 - 屬性constructor-arg中,無需指定屬性名,只需填寫屬性值。 - 屬性constructor-arg中,所有的屬性值均是String型別,Spring會在賦值的時候自動進行型別轉換。
2.注入物件引用 假設Person類中有一個Father型別的屬性,並且新增引數為Father的建構函式:
class Person{
private long id;
private String name;
private Father father;
public Person(Father father){
this.father = father;
}
……省略所有setter、getter函式……
}
此時,建構函式的引數是一個引用型別的變數,我們可以做如下處理:
<!-- 首先建立Father型別的bean -->
<bean id="father" class="com.njupt.Father">
<constructor-arg value="柴毛毛的爸爸"/>
<constructor-arg value="1"/>
</bean>
<!-- 通過ref引用father物件 -->
<bean id="person" class="com.njupt.Person">
<constructor-arg ref="father"/>
</bean>
3.通過工廠建立bean 如果一個類是工廠類,它沒有建構函式,因此我們沒有辦法通過構造器來初始化這個物件。但工廠模式會提供給我們一個靜態函式,用來獲取工廠物件,那麼在配置bean的時候做如下操作:
<bean id="person" class="com.njupt.Person" factory-method="getIntance"/>
對於工廠類,我們需要呼叫getInstance來獲取工廠物件,因此在配置bean的時候,我們需要通過factory-method屬性告訴Spring,獲取這個工廠物件的函式是getInstance。
屬性注入
通過上面我們瞭解到,Spring通過bean標籤下的constructor-arg標籤為建構函式注入引數值,接下來介紹Spring通過property標籤為成員變數注入初始值。
1.注入基本型別的值 為Person物件的name屬性注入一個初始值“chaiMaoMao”: - name:屬性名 - value:屬性值
<bean id="person" class="com.njupt.Person">
<property name="name" value="chaiMaoMao"/>
</bean>
注意:在編寫配置檔案的時候,Spring中value的全是String型別,但Spring會在執行的時候自動將其轉換為相應的型別。
2.注入物件引用 在bean中通過ref屬性注入一個引用型別的變數。如:Person類中有一個Father型別的屬性father,如果我們需要將一個father物件注入Person的father屬性中,需要進行如下操作:
<!-- 引用name為father的bean注入給Person的father屬性 -->
<bean id="person" class="com.njupt.Person">
<property name="father" ref="father"/>
</bean>
<!-- 定義name為father的bean -->
<bean id="father" class="com.njupt.Father">
<constructor-arg value="柴毛毛的爸爸"/>
<constructor-arg value="1"/>
</bean>
3.注入內部bean 如果一個bean僅供某一個bean使用,那麼可以將這個bean宣告為內部bean。如:name為father的bean只允許注入給name為person的bean,那麼就將father這個bean以放在person的內部,如下所示:
<bean id="person" class="com.njupt.Person">
<property name="father">
<bean class="com.njupt.Father" />
</property>
</bean>
注意: 1. 內部bean沒有名字,只適應於一次性注入,不能被其他bean引用。 2. 注入內部bean不僅限於屬性注入,也可用於構造器注入,如下所示:
<bean id="person" class="com.njupt.Person" init-method="createInstance" destory-method="destoryInstance">
<constructor-arg>
<bean class="com.njupt.Father" />
</constructor-arg>
</bean>
Bean的作用域
在Spring中,預設情況下bean都是單例。也就是說,當我們向Spring請求一個bean物件時,Spring總給我們返回同一個bean物件。 **注意:**Spring 中所說的“單例”與Java中的單例稍有不同。Spring中的單例是指:在同一個ApplicationContext中相同名字的bean物件是同一個;而Java中的單例是指:整個JVM中單例的物件只有一個。 當然,我們可以通過改變bean標籤的scope引數來設定bean的作用域。常用的scope對應的值有: - singleton:在同一個Spring Context中,一個bean只有一個例項物件。(預設) - prototype:每次向Spring請求一個bean物件,Spring都會建立一個新的例項。
初始化和銷燬Bean
如果需要在bean物件初始化之後或銷燬之前做一些額外的操作的話,可以作如下配置: 1. 首先需要在bean中定義函式,供Spring建立該類物件或銷燬該物件的時候呼叫:
public void createInstance(){
System.out.println("物件被建立啦!");
}
public void destoryInstance(){
System.out.println("物件被銷燬啦!");
}
- 在XML中作如下配置: 告訴Spring,這個bean在被建立的時候呼叫這個類中哪個函式,這個類被銷燬的時候呼叫這個類中的哪個函式。
<bean id="person" class="com.njupt.Person" init-method="createInstance" destory-method="destoryInstance">
<constructor-arg ref="father"/>
</bean>
如果所有的bean在初始化或銷燬的時候都需要呼叫函式,那麼可以在beans標籤中設定一個全域性的引數:default-init-method和default-destroy-method。這樣,這個beans標籤下的所有bean在建立或銷燬時都會呼叫createInstance()和destoryInstance()。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.5.xsd"
default-init-method="createInstance"
default-destory-method="destoryInstance">
</beans>
裝配集合
到此為止,不管是裝配基本型別還是裝配物件的引用,都是在裝配單個屬性,那麼該如果裝配一個集合呢?
集合元素 |
用途 |
---|---|
list |
用於裝配單值集合,允許重複 |
set |
用於裝配單值集合,不允許重複 |
map |
用於裝配鍵值對集合,key和value可以為任意型別 |
props |
用於裝配鍵值對集合,key和value只能為String型別 |
- 對於單個值的集合,如陣列、List、Set,均可以用list標籤來裝配,list標籤和set標籤的不同之處僅僅是前者允許重複,而後者不允許重複。 - 對於鍵值對集合,可以使用set標籤或props標籤,兩者的區別是:前者的key和value可以是任何型別,而後者的key和value只能是String型別。
1.裝配List:
<bean id="person" class="com.njupt.Person">
<property name="list">
<list>
<ref bean="a"/>
<ref bean="b"/>
<ref bean="c"/>
</list>
</property>
</bean>
2.裝配Map:
<bean id="person" class="com.njupt.Person">
<property name="map">
<map>
<entry key="key_a" value-ref="a"/>
<entry key="key_b" value-ref="b"/>
<entry key="key_c" value-ref="c"/>
</map>
</property>
</bean>
3.裝配props:
<bean id="person" class="com.njupt.Person">
<property name="map">
<props>
<prop key="key_a">value_a</prop>
<prop key="key_b">value_b</prop>
<prop key="key_c">value_c</prop>
</props>
</property>
</bean>
SpEL表示式
SpEL=Spring Express Language 這種表示式用在Spring的配置檔案中,可以直接獲取某個bean的某一個屬性值或獲得一個函式的執行結果,相當屌! SpEL表示式不難,下面舉幾個例子相信聰明的你就能理解了。
- 引用一個bean的屬性值
<bean id="person" class="com.njupt.Person">
<property name="name" value="#{father.name}" />
</bean>
- 引用一個bean的函式的執行結果
<bean id="person" class="com.njupt.Person">
<property name="name" value="#{father.getName()}" />
</bean>
- 引用Java中某個靜態函式的執行結果
<bean id="person" class="com.njupt.Person">
<property name="name" value="#{T(java.lang.Math).random()}" />
</bean>
- 數值運算
<bean id="person" class="com.njupt.Person">
<property name="id" value="#{count.id + 100}" />
</bean>
- 字元連線
<bean id="person" class="com.njupt.Person">
<property name="name" value="#{father.name +' '+ mother.name}" />
</bean>
- 比較運算
<bean id="person" class="com.njupt.Person">
<property name="equal" value="#{father.name == mother.name}" />
</bean>
- 訪問集合成員
<bean id="person" class="com.njupt.Person">
<property name="name" value="#{list['chaiMaoMao']}" />
</bean>
<bean id="person" class="com.njupt.Person">
<property name="name" value="#{list[2]}" />
</bean>
- 查詢集合成員
<bean id="person" class="com.njupt.Person">
<property name="name" value="#{list.?[age gt 20]}" />
</bean>
- 投影集合
<bean id="person" class="com.njupt.Person">
<property name="names" value="#{list.![name]}" />
</bean>