定義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 上自行下載。