定義bean時有個abstract屬性,可以設定為true或false,預設為false。
1
2
3
4
|
<bean id="animal" class="Animal" abstract="true">
<property name="name" value="elephant"/>
<property name="legs" value="4”/>
</bean>
|
這裡定義了一個叫elepahnt的animal bean,有4條腿,它與其他bean不同之處是abstract屬性為true。這意味著什麼?意味著這個bean不能被例項化,不能通過ApplicationContext.getBean()的方式來獲取到該bean,也不能使用ref屬性引用這個bean。否則會丟擲BeanIsAbstractException的異常。
你可能會問?坑爹那?宣告一個bean不能被例項化,那有何用?
當然有用,Spring框架開發者也不是一幫吃飽了沒事幹的人,設計一些沒用的功能出來。
這要配合著parent屬性來用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<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="animal" class="Animal" abstract="true">
<property name="legs" value="4"/>
</bean>
<bean id="monkey" parent="animal">
<property name="name" value="dudu"/>
</bean>
</beans>
|
這裡有兩個bean,一個是animal,指定legs是4,另一個是monkey,通過parent的屬性指向animal,指定name為dudu。聰明的讀者可能已經猜出來了,parent屬性就是子bean可以繼承父bean中的屬性,並且在子bean中可以過載對應的屬性。雖然我們沒顯式的指定monkey的legs為4,其實它已經從父bean animal中繼承了這個屬性。這樣的好處是如果在定義大量bean時,發先大量bean存在重複屬性定義時,可以抽取一個抽象bean出來,實現這些重複的屬性定義,讓其他bean都使用parent屬性指向這個抽象bean。這樣可以大大簡化bean的配置。
除了使用parent直接引用父bean的class外,另外也可以使用自定義的class。
Monkey.java
1
2
3
4
5
6
7
8
9
10
11
12
|
public class Monkey extends Animal {
private boolean canDrawing;
public boolean isCanDrawing() {
return canDrawing;
}
public void setCanDrawing(boolean canDrawing) {
this.canDrawing = canDrawing;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<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="animal" class="Animal" abstract="true">
<property name="legs" value="4"/>
</bean>
<bean id="smartMonkey" class="Monkey" parent="animal">
<property name="name" value="smallDudu"/>
<property name="canDrawing" value="true"/>
</bean>
</beans>
|
這樣smartMonkey自動繼承了父bean中的legs屬性,同時它的class型別也是一個新型別。
有人可能要問了,子bean的class與父bean中的class一定要是繼承關係嗎?答案是否定的。
請看這個修改後的Monkey class,其本身並未從Animal繼承。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public class Monkey {
private boolean canDrawing;
private String name;
private int legs;
public boolean isCanDrawing() {
return canDrawing;
}
public void setCanDrawing(boolean canDrawing) {
this.canDrawing = canDrawing;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLegs() {
return legs;
}
public void setLegs(int legs) {
this.legs = legs;
}
}
|
然後還配置同樣的bean。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<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="animal" class="Animal" abstract="true">
<property name="legs" value="4"/>
</bean>
<bean id="smartMonkey" class="Monkey" parent="animal">
<property name="name" value="smallDudu"/>
<property name="canDrawing" value="true"/>
</bean>
</beans>
|
依然能夠正常工作,並且smartMonkey中的legs還是4。
這說明了Spring中使用parent繼承父bean中的屬性並不需要子bean和父bean的class在一個繼承樹上。父bean更像一個模板,子bean能夠自動使用父bean中的配置而已。唯一需要注意的是在父bean中定義的屬性在子bean中都要存在。
那可能有人就有個大膽的猜想了,可不可以定義一個沒有class型別的父bean那?這個bean反正不能例項化,只用來讓子bean繼承屬性。答案是肯定的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<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="animal" abstract="true">
<property name="legs" value="4"/>
</bean>
<bean id="monkey" parent="animal" class="Animal">
<property name="name" value="dudu"/>
</bean>
<bean id="smartMonkey" class="Monkey" parent="animal">
<property name="name" value="smallDudu"/>
<property name="canDrawing" value="true"/>
</bean>
</beans>
|
上面的定義依然可以工作。
多說一點,parent也支援對集合屬性的繼承。比如在父bean中定義了一個屬性為List或Map,子bean中也能繼承到該List或Map,更強大的是子bean還可以對List或Map進行合併。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<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="sampleAccounts" abstract="true">
<property name="accounts">
<map>
<entry key="Bob" value="001"/>
<entry key="John" value="002"/>
</map>
</property>
</bean>
<bean id="accountService" parent="sampleAccounts" class="AccountService">
<property name="accounts">
<map merge="true">
<entry key="Michael" value="003"/>
<entry key="Joel" value="004"/>
</map>
</property>
</bean>
</beans>
|
在子bean中使用的map元素上使用merge=“true”就可以和父bean中的map條目進行合併。如果指定為false則不會合並,只會使用子bean中定義的map條目。
本例中的原始碼請在我的GitHub上自行下載。