Spring-Context之九:在bean定義中使用繼承


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM