Spring框架自學之路(三)
(03Day)
(1)Bean的自動裝配
在前面的例子中我們為Bean裝配Bean很明顯都是手動裝配的,那麼既然有手動裝配那有沒有自動裝配呢?顯然是有的。那麼自動裝配又該如何使用呢?其實很簡單,來看看吧。
為Bean設定自動裝配只需要在Bean中設定autowire並指定自動裝配的模式就行了。
atuowire有三種裝配模式分別是:
- byType:根據型別進行自動裝配,若IOC容器中有多個目標與目標Bean型別一致,這種情況下會丟擲異常。
- byName:根據名稱完成自動裝配:必須將目標Bean的屬性名和名稱設定的完全相同,IOC會根據Get方法獲取。
- constructor:通過構造方法進行自動裝配,當Bean中存在多個構造方法的時候,這種配置方法會很複雜,因此不推薦使用。
在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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id = "address" class="com.autowire.Address" p:city="廈門" p:street="集美"></bean> <bean id = "car" class="com.autowire.Car" p:brand="奧迪" p:price="300000"></bean> <!-- 手動裝配 <bean id = "person" class="com.autowire.Person" p:name="李四" p:car-ref="car" p:address-ref="address"></bean> --> <!-- 使用autowire自動裝配,屬性指定自動裝配的方式 byNmae是根據該Bean的名字和當前 Bean的setter方法除去set後的方法名進行自動裝配,若沒有匹配的方法,則不裝配 byType是根據該Bean的型別和當前Bean的屬性的型別進行自動裝配。注意:若IOC容器中有一個以上的該型別匹配的bean,則丟擲異常。 --> <bean id = "person" class="com.autowire.Person" p:name="李四" autowire="byName"></bean> </beans>
測試類
package com.autowire; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main4 { public static void main(String[] args) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-autowire.xml"); Person person = (Person) ctx.getBean("person"); System.out.println(person); } }
1.一旦使用自動裝配,那麼該Bean所有的引用屬性都必須使用自動裝配,不能有的使用自動裝配,有的使用手動裝配。
2.要麼根據型別自動裝配,要麼根據屬性名自動裝配,不能兩者同時使用。
3.一般情況下,在實際的專案中很少使用自動裝配功能,因為和自動裝配功能所帶來的好處比起來,明確清晰的配置文件更有說服力一些。
(2)Bean之間的關係
2-1 繼承
說到繼承,也許會想到我們java中面向物件的繼承,但是在這繼承並不是指java中面向物件的父類子類繼承,而是
指配置上的繼承。在spring中Bean的繼承其實很簡單,主要就是在Bean的元素中新增parent = “繼承的Bean”
來看看程式碼吧。
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 不使用繼承的方式
<bean id = "address1" class="com.autowire.Address"
p:city="廈門" p:street="集美區"></bean>
<bean id = "address2" class="com.autowire.Address"
p:city="廈門" p:street="海滄區"></bean>
-->
<!-- 使用繼承的方式 parent 代表要繼承的Bean 同時也可以繼承模版,模版就是Bean 加上abstract = “true” -->
<bean id = "address1" class="com.autowire.Address"
p:city="廈門" p:street="集美區"></bean>
<!-- 繼承address1 Bean -->
<bean id = "address2" parent="address1"
p:street="海滄區"></bean>
<!-- 定義一個模版,模版上可以不寫class路徑,也可以寫,同時abstract為true的bean是不會被
IOC容器初化的,只能用來被繼承配置。同理若一個Bean的Class沒有指定,則該Bean必須是一個
抽象Bean。
-->
<bean id = "address" p:city="廈門" p:street="集美區" abstract="true"></bean>
<!-- 繼承模版 並不是所有的元素的都會被繼承 例如 abstract就不會被繼承 -->
<bean id = "address3" class="com.autowire.Address" parent="address"
p:street="思明區"></bean>
</beans>
2-2 依賴
那麼何為依賴呢,通俗來說就是Bean1依賴於Bean2,那麼Bean1建立的時候在IOC容器中必須要存在Bean2。
廢話不多說,具體細節用程式碼來說明。
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 不實用繼承的方式
<bean id = "address1" class="com.autowire.Address"
p:city="廈門" p:street="集美區"></bean>
<bean id = "address2" class="com.autowire.Address"
p:city="廈門" p:street="海滄區"></bean>
-->
<!-- 使用繼承的方式 parent 代表要繼承的Bean 同時也可以繼承模版,模版就是Bean 加上abstract = “true” -->
<bean id = "address1" class="com.autowire.Address"
p:city="廈門" p:street="集美區"></bean>
<!-- 繼承address1 Bean -->
<bean id = "address2" parent="address1"
p:street="海滄區"></bean>
<!-- 定義一個模版,模版上可以不寫class路徑,也可以寫,同時abstract為true的bean是不會被
IOC容器初化的,只能用來被繼承配置。同理若一個Bean的Class沒有指定,則該Bean必須是一個
抽象Bean。
-->
<bean id = "address" p:city="廈門" p:street="集美區" abstract="true"></bean>
<!-- 繼承模版 並不是所有的元素的都會被繼承 例如 abstract就不會被繼承 -->
<bean id = "address3" class="com.autowire.Address" parent="address"
p:street="思明區"></bean>
<!-- 依賴Bean的配置 此時若是car沒在IOC容器中定義,那麼執行程式的時候會丟擲異常
所以說依賴Bean就是配置Person的時候,必須有一個car與之關聯,也就是說person這個
Bean依賴與Car這個Bean。依賴就是為了讓建立person這個Bean之前IOC容器中必須存
在Car這個Bean,如果需要依賴多個Bean可以通過逗號或者空格的方式配置。
-->
<bean id = "car" class="com.autowire.Car"
p:brand="賓士" p:price="5000000"></bean>
<bean id = "person" class="com.autowire.Person"
p:name="Garon" p:address-ref="address3" depends-on="car"></bean>
</beans>
測試類
package com.relation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.autowire.Address;
import com.autowire.Person;
public class Main5 {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-relation.xml");
Address address = (Address) ctx.getBean("address1");
System.out.println(address);
address = (Address) ctx.getBean("address2");
System.out.println(address);
address = (Address) ctx.getBean("address3");
System.out.println(address);
Person person = (Person) ctx.getBean("person");
System.out.println(person);
}
}
(3)Bean的作用域
預設情況下在IOC容器下配置的Bean是單例模式的,也就是說IOC容器只會為這個Bean節點建立一個例項物件,每次呼叫GetBean方法都會返回同一個Bean。
那麼如果配置Bean 的作用域呢?只需要在Bean的屬性中配置 scope元素就行了,scope元素有以下4個元素:
1)singleton:單利的,預設值,容器在初始化的時候建立bean例項,整個容器的生命週期只建立這一個Bean。
2)prototype:原型的,容器在初始化的時候不建立Bean,在每一次請求的時候都會建立一個新的例項並返回。
3)request:每次http請求將會有各自的bean例項,類似於prototype。
4)session:在一個http session中,一個bean定義對應一個bean例項。
話不多說上程式碼。
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 使用Bean的scope屬性來配置bean的作用域
singleton:單利的,預設值,容器在初始化的時候建立bean例項,整個容器的生命週期只建立這一個Bean。
prototype:原型的,容器在初始化的時候不建立Bean,在每一次請求的時候都會建立一個新的例項並返回。
request:每次http請求將會有各自的bean例項,類似於prototype。
session:在一個http session中,一個bean定義對應一個bean例項。
-->
<bean id= "car1" class="com.autowire.Car"
p:brand="寶馬" p:price="350000" scope="prototype"></bean>
</beans>
測試類
package com.scope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.autowire.Car;
public class Main6 {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-scope.xml");
Car car1 = (Car) ctx.getBean("car1");
Car car2 = (Car) ctx.getBean("car1");
System.out.println(car1 == car2);
}
}
(4)使用外部屬性檔案
在實際開發中我們的spring配置檔案會非常的複雜,那麼如果我們需要修改系統部署的細節資訊,是不是要在spring配置檔案中找到對應的檔案進行修改呢?很明顯這樣做非常的麻煩而且容易出錯,於是spring引入了外部屬性檔案這種配置方法使得這些部署的細節和Bean配置相分離。
那麼如何做呢?需要在src目錄下建立一個字尾為properties的檔案,並在裡面配置好資訊後,只需要在spring的配置檔案中匯入context:properties這個名稱空間使用<context:properties-placeholder location=“classpath:外部檔案的名字”>就可以了。這樣在Bean的配置檔案就可以使用類似於EL表示式的方式${var}取值.
外部屬性檔案類似於這樣寫
這樣如果要取user這個值只需要再對應的value中使用${user}就可以取到root這個值,以後需要修改基礎的配置資訊,只需要到外部屬性檔案裡修改就行了,這樣是不是更方便且不容易出錯。