Spring容器裝配Bean流程
首先Bean的裝配有以下四種方式:
- XML Beans
- 注解(@Autowired)
- Java類配置
- Groovy動態語言配置
Bean的配置信息定義了Bean的實現及依賴關系,Spring容器根據各種形式的Bean配置信息在容器內部建立Bean定義注冊表;然后根據注冊表加載、實例化Bean,并建立Bean和Bean之間的依賴關系;最后將這些準備就緒的Bean放到Bean緩存池中,以供外層的應用進行調用。
基于XML的配置
在Spring低版本中,XML中采用的是基于DTD的配置方式,Spring4.0配置升級后是基于Schema的配置方式,雖然升級是向后兼容的,但后者是我們首選的XML配置方式。
一個基本的基于Schema的XML配置模板如下:
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
- xmlns="http://www.springframework.org/schema/beans" 默認命名空間
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 自定義命名空間,xsi是簡稱
- xsi:schemaLocation 是個命名空間對應的schema文件
指定命名空間的Schema文件地址有兩個用途:XML解析器可以獲取Schema文件并對文檔進行格式合法性校驗;在IDE下可以自動補全代碼。
裝配一個Bean
在XML中的基本配置如下:
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="car" class="com.oyty.Car"/>
</beans>
在裝配Bean時要指定一個id,這個id是唯一的,外部應用可以通過getBean(id)
獲取Bean的實例,如果不指定,Spring將全限定類名dessert.Cake
作為Bean的唯一標識。
Spring支持兩種依賴注入方式,屬性注入和構造函數注入,屬性注入就是通過setXxx()
方法注入Bean的屬性值或依賴對象,這種注入方式具有可選擇性和靈活性高的優點,所以這是實際開發中最常采用的注入方式。
屬性注入
屬性注入要求Bean提供一個默認的構造函數,并為需要注入的屬性提供對應的Setter方法。Spring先調用Bean的默認構造函數實例化Bean對象,然后通過反射
的方式調用Setter方法注入屬性值,實例如下:
public class Car {
private String brand;
private String color;
private int maxSpeed;
public void setBrand(String brand) {
this.brand = brand;
}
public void setColor(String color) {
this.color = color;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
}
xml中的配置:
<?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.xsd">
<bean id="car" class="com.oyty.Car">
<property name="brand" value="Tesla" />
<property name="color" value="blue" />
<property name="maxSpeed" value="300" />
</bean>
</beans>
Spring只會檢查xml中配置的屬性有沒有對應的setXxx()
方法,至于方法如何實現、有沒有對應的屬性則不做要求。
構造函數注入
構造函數注入可以保證一些必要的屬性在Bean實例化時就得到設置,確保Bean在實例化后就可以使用。
按類型匹配入參
帶參的構造函數:
public Car(String brand, int maxSpeed) {
this.brand = brand;
this.maxSpeed = maxSpeed;
}
xml中的配置:
<bean id="car" class="com.oyty.Car">
<constructor-arg type="java.lang.String" value="Tesla" />
<constructor-arg type="java.lang.Integer" value="300" />
</bean>
按索引匹配入參
我們知道Java語言本身通過入參的類型和順序區分不同的重載方法,如果Car的構造參數中有兩個相同的類型,那么僅通過type就無法確定了,這個時候就要通過入參索引的方式進行確定。
public Car(String brand, String color, int maxSpeed) {
this.brand = brand;
this.color = color;
this.maxSpeed = maxSpeed;
}
<bean id="car" class="com.oyty.Car">
<constructor-arg index="0" value="Tesla" />
<constructor-arg index="1" value="black" />
<constructor-arg index="2" value="300" />
</bean>
聯合使用類型和索引入參
如果有下面兩個構造方法,那么單一的一種匹配方式就不奏效了:
public Car(String brand, String color, int maxSpeed) {
this.brand = brand;
this.color = color;
this.maxSpeed = maxSpeed;
}
public Car(String brand, String color, double price) {
this.brand = brand;
this.color = color;
this.price = price;
}
這個時候就要聯合使用類型和索引來匹配入參:
<bean id="car" class="com.oyty.Car">
<constructor-arg index="0" type="java.lang.String" value="Tesla" />
<constructor-arg index="1" type="java.lang.String" value="black" />
<constructor-arg index="2" type="double" value="1000000" />
</bean>
顯示地指定index和type是一種良好的配置習慣
循環依賴問題
如果兩個Bean都是構造函數配置,入參相互引用對方的實例,這會發生類似于線程死鎖的循環依賴問題,這樣Spring容器是無法啟動的,解決方法就是將構造函數注入改為屬性注入。
注入參數為其它Bean
前面的各種配置方法參數都是基本類型,如果參數是另一個Bean,該如何配置呢?
public class Boss {
private Car car;
public void setCar(Car car) {
this.car = car;
}
}
屬性注入依賴其它的Bean:
<bean id="boss" class="com.oyty.Boss">
<property name="car" ref="car" />
</bean>
ref中bean所指定的car
為xml配置中Car的Bean配置的名稱。
內部Bean
如果car Bean只被boss Bean引用,而不被容器中任何其它的Bean引用,則可以將car以內部Bean的方式注入到Boss中:
<bean id="boss" class="com.oyty.Boss">
<property name="car">
<bean class="com.oyty.Car">
<property name="brand" value="Tesla" />
<property name="maxSpeed" value="300" />
<property name="color" value="black" />
</bean>
</property>
</bean>
為某一個屬性注入null值
如何我們進行如下配置:
<bean id="car" class="com.oyty.Car">
<property name="color"><value></value></property>
</bean>
color屬性注入的并不是null值,而是一個空字符串,如果要注入null值,需要使用特定的標簽:
<bean id="car" class="com.oyty.Car">
<property name="color"><value></value></property>
<property name="brand"><null/></property>
</bean>
集合類型屬性
List & Set
private List favorities = new ArrayList();
public List getFavorities() {
return favorities;
}
public void setFavorities(List favorities) {
this.favorities = favorities;
}
<bean id="boss1" class="com.oyty.Boss">
<property name="favorities">
<list>
<value>看書</value>
<value>打球</value>
<value>賽車</value>
</list>
</property>
</bean>
# 如果favorities是Set類型的話
<bean id="boss1" class="com.oyty.Boss">
<property name="favorities">
<set>
<value>看書</value>
<value>打球</value>
<value>賽車</value>
</set>
</property>
</bean>
Map
private Map jobs = new HashMap();
public Map getJobs() {
return jobs;
}
public void setJobs(Map jobs) {
this.jobs = jobs;
}
<bean id="boss2" class="com.oyty.Boss">
<property name="jobs">
<map>
<entry key="AM" value="回見客戶" />
<entry key="PM" value="公司內部會議" />
</map>
</property>
</bean>
Properties
private Properties mails = new Properties();
public Properties getMails() {
return mails;
}
public void setMails(Properties mails) {
this.mails = mails;
}
<bean id="boss3" class="com.oyty.Boss">
<property name="mails">
<props>
<prop key="jobMail">oyty-job@gmail.com</prop>
<prop key="lifeMail">oyty-life@gmail.com</prop>
</props>
</property>
</bean>
通過util命名空間配置集合類型的Bean(略)
使用p標簽簡化配置
<?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="car1" class="com.oyty.Car"
p:brand="Tesla"
p:color="black"
p:maxSpeed="300"/>
</beans>
Bean的作用域
- singleton 在Spring容器中只存在一個Bean實例,Bean以單例方式存在
- prototype 每次從容器中調用Bean時,都返回一個新的實例
- request 每次HTTP請求都會創建一個新的Bean,該作用域僅適用于WebApplicationContext環境
- session 同一個HTTP session共享一個Bean,比如購物車bean,不同的HTTP session使用不同的bean,該作用域僅適用于WebApplicationContext環境
小結
這篇文章主要講解了基于XML配置Bean的方式,兩種依賴注入方式,屬性注入和構造方法注入,分別的配置如何,以及各種類型參數的配置。后面講解基于注解和Java類的配置。