跟著柴毛毛學Spring(3)——簡化Bean的配置
簡化Spring的配置主要分為兩類: 1. 自動裝配 2. 自動掃描
下面就詳細介紹這兩種簡化配置的方式。
自動裝配
自動裝配的種類
- byName:根據屬性的名字自動裝配
- byType:根據屬性的型別自動裝配
- constructor:根據構造器的引數型別自動裝配
- autodetect:最佳自動裝配。首先採用constructor自動裝配,若沒有發現與構造器相匹配的Bean時,採用byType進行自動裝配。
使用XML實現自動裝配
- byName:根據屬性的名字裝配 在bean標籤中新增屬性autowire=”byName”。當Spring啟動時,會尋找與person中成員變數名字相同的bean,並將該bean注給person的成員變數。
<bean id="person" class="com.njupt.Person" autowire="byName">
</bean>
- byType:根據屬性的型別裝配 在bean標籤中新增屬性autowire=”byName”。當Spring啟動時,會尋找與person中成員變數型別相同的bean,並將該bean注給person的成員變數。
<bean id="person" class="com.njupt.Person" autowire="byType">
</bean>
byType的缺點:如果某一型別的bean有多個,那Spring在通過byType為屬性尋找同類型的bean時就會丟擲異常。 解決方案: - 為相同型別的bean設定是否首選 在需要被首選的bean中作如下設定:
<bean id="person" class="com.njupt.Person" primary="true">
</bean>
在不需要被首選的bean中作如下設定:
<bean id="person" class="com.njupt.Person" primary="false">
</bean>
- 取消某一些相同型別bean的候選資格 使用auto-candidate屬性取消某些bean的候選資格,Spring在為屬性尋找同類型的bean時直接排除這些bean。
<bean id="person" class="com.njupt.Person" default-candidate="false"> </bean>
- constructor:根據構造器的引數的型別裝配 autowire設定為constructor後,Spring會尋找與建構函式的引數型別相同的bean,並注入給這個建構函式。
<bean id="person" class="com.njupt.Person" autowire="constructor">
</bean>
構造器的自動裝配本質上仍是通過byType進行裝配,只不過autowire=”constructor”時,Spring會對構造器的引數進行自動裝配,而autowire=”byType”時,Spring會對bean的成員變數進行自動裝配。
構造器的自動裝配和byType自動裝配具有相同的缺點:當某一型別的bean有多個時,Spring無法確定究竟選擇哪個bean,就直接丟擲異常。 此外,構造器的自動裝配還有個獨特的缺點:當構造器有多個時,Spring也無法選擇究竟初始化哪個構造器,因此也直接跑出異常。
- autodetect:最佳自動裝配。Spring要初始化一個設定了autowire=”autodetect”的bean時,首先採用構造器裝配,若沒有發現與構造器相匹配的Bean或構造器有多個時,就採用byType對屬性進行裝配。
使用預設自動裝配 上述自動裝配的方法都是針對單個bean,如果要讓beans下的所有bean均使用某種自動裝配策略,那麼在beans標籤中增加如下配置:
default-autowire="byType"
- 注意1:在beans中設定了default-autowire後,這個引數僅對當前beans標籤之間的bean有效。
- 注意2:採用預設自動裝配後,仍然可以在bean中設定特有的自動裝配策略,bean中的自動裝配策略會覆蓋預設策略。
- 注意3:使用了自動裝配後,我們仍然可以在bean中通過constructor-arg屬性和property屬性對bean進行顯示裝配。 這種混合使用顯示裝配和自動裝配的方式能夠成功地解決byType出現的不確定性問題。
- 注意4:如果使用了constructor來實現構造器引數的自動裝配,那麼就不能混合使用autowire=”constructor”屬性和constructor-arg標籤。
使用註解實現自動裝配
使用註解裝配其實就是把原本XML中bean中的autowire=”xxx”屬性搬到了Bean類的Java程式碼中了。功能上沒啥差別。 下面就來介紹如何使用註解實現自動裝配。
1. 開啟註解自動裝配
在beans中作如下配置:
<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">
<context:annotation-config>
</beans>
2. 使用@Autowired標註需要自動裝配的函式或屬性
當Bean中的屬性、函式被標記@Autowired後,Spring在建立這個bean的物件時,會通過byType尋找與屬性、函式引數相同型別的bean進行自動裝配。 - 用@Autowired標註建構函式
@Autowired
public Person(String name,long id){
this.name = name;
this.id = id;
}
- 用@Autowired標註普通函式
@Autowired
public void createInstance(){
System.out.println("物件被建立啦!");
}
- 用@Autowired標註屬性
@Autowired
private Father father;
@Autowired本質上採用byType進行自動裝配,因此也存在與byType一樣的問題:若同一型別的bean有多個時,或找不到該型別的bean,Spring就會丟擲異常。
@Autowired弊端的應對策略
- 若同一型別的bean有多個 若採用xml設定bean的自動裝配,則可以使用顯示裝配的方式,手動設定需要注入的引數,而使用註解自動裝配時,可以使用@Qualifier縮小候選bean的範圍,具體操作如下:
@Autowired
@Qualifier("father")
private Father father;
@Qualifier(“ID”)會根據bean的id為father裝配。
- 若找不到某一型別的bean 如果bean中的某些屬性、引數不需要初始化值也能接受的話,那就為該屬性或引數的@Autowired新增required屬性:
@Autowired(required="false")
public Person(String name,long id){
this.name = name;
this.id = id;
}
此時,如果Spring找不到與建構函式的引數相同型別的bean的話,就賦上null。 注意:若一個bean有多個建構函式時,只有一個建構函式可以設為@Autowired(required=true),其餘的建構函式都只能設為@Autowired(required=false)
在註解中使用SpEL表示式
通過前面學習我們知道,在Spring的XML配置中,可以使用SpEL表示式來實現手動裝配。同樣,在註解中也可以使用SpEL表示式實現手動裝配。 - 將名為father的bean注入給建構函式:
@Value("#{father}")
public Person(Father father){
this.father = father;
}
- 將father物件中的id注入給id:
@Value("#{father.id}")
public void setId(long id){
this.id = id;
}
自動檢測
自動裝配能夠減少bean標籤下property標籤和constructor-arg標籤的數量,而自動檢測能降低bean標籤的數量。
1. 開啟Spring的自動檢測
腰開啟自動檢測功能,需要在XML的beans標籤中作如下配置: - base-package: 表示要掃描的包
<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">
<context:component-scan base-package="com.xxx"></context:component-scan>
</beans>
2. 為需要自動減的bean新增@Component註解
要讓一個Java類變成一個Bean,需要在類上加上@Component註解。Spring在啟動的時候會到base-package指定的包下尋找被@Component標記的類,把他們初始化為bean,儲存在SpringContext中。 - 將型別的小寫作為bean的名字:
@Component
class Person{
}
- 指定bean的名字:
@Component("person")
class Person{
}
3. 過濾被掃描的bean
使用Java代替XML配置
雖然使用註解已經大大減少Spring中的XML配置,但仍然需要少量的XML配置,我們可以將XML配置用Java程式碼實現,從而完全避免了XML配置。
1. 定義一個Spring配置類
用@Configuration標籤標註一個類,表示這個類是Spring的配置類:
@Comfiguration
class Person{
……
}
2. 宣告一個bean
在Spring的配置類中,使用@Bean標籤標註一個bean。 - 函式名:bean的id - 返回值:bean的型別 - 函式體:初始化這個bean
@Comfiguration
class Person{
@Bean
public Person person(){
//構造器注入
Person person = new Person("柴毛毛");
//屬性注入
person.setAge(22);
return person;
}
}
3. 使用Java進行注入
在採用Java進行Spring的配置中,對bean屬性和構造器的注入非常簡單,只需在函式中操作即可:
@Comfiguration
class Person{
@Bean
public Person person(){
return new Person();
}
}
採用Java代替XML配置的好處
在XML配置中,bean的型別是用String表示的,因此只有在執行結點才能發現bean的型別是否寫錯;而在Java配置中,在編譯階段就能發現bean的型別是否出錯,從而能夠儘早地發現錯誤。