我們在應用Spring時,在一般的設計時,肯定要用的抽象類。那在Spring中怎么樣配置這些抽象Bean呢。請看下面:
如果兩個bean 之間的配置信息非常相似,可利用繼承來減少重復配置工作。
繼承是指子bean 定義可從父bean 定義繼承部分配置信息,也可覆蓋特定的配置信息,或者添加一些配置。使用繼承配置可以節省很多的配置工作。在實際應用中,通用配置會被配置成模板,可供子bean 繼承。
使用abstract 屬性
正如前面所介紹的,通用的配置會被配置成模板,而模板不需要實例化,僅僅作為子bean 定義的模板使用。而ApplicationContext 默認預初始化所有的singleton bean 。使用abstract 屬性,可以阻止模板bean 被預初始化。abstract 屬性為true 的bean 稱為抽象bean ,容器會忽略所有的抽象bean 定義,預初始化時不初始化抽象bean。如果沒有定義abstract 屬性,該屬性默認為false 。如下配置文件定義了一個抽象bean ,該抽象bean 作為模板使用:
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
|
public class SteelAxe implements Axe { //count 是個狀態值,每次執行chop 方法該值增加1 private int count = 0 ; public SteelAxe(){ System.out.println( "Spring實例化依賴bean: SteelAxe 實例.. ." ); } //測試用方法 public String chop(){ return "鋼斧砍柴真快" + ++count; } } public class Chinese implements Person //面向Axe 接口編程,而不是具體的實現類 private Axe axe; //默認的構造器 public Chinese(){ System.out.println( "Spring實例化主調bean: Chinese 實例... " ); } //設值注入所需的setter 方法 public void setAxe( Axe axe){ System.out.pr工ntln ( " Spring 執行依賴關系注入..." ); this .axe = axe; } //實現Person 接口的useAxe 方法 public void useAxe(){ System.out.println(axe.chop()); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<? xml version = "1.0" encoding = "gb2312" ?> <!一指定Spring 配置文件的dtd> < lDOCTYPE beans PUBL工C "-//SPRING//DTD BEAN//EN" ''http://www.springframework.org/dtd/spring-beans.dtd''> <!一Spring 配置文件的根元素一〉 < beans > < bean id = "steelAxe" class = "lee.SteelAxe" /> <!… 通過abstract 屬性定義該bean 是抽象bean--> < bean id = "chineseTemplate" class = "lee.Chinese" abstract = "true" > <!一定義依賴注入的屬性一〉 < property name = "axe" > < ref local = "steelAxe" /> </ property > </ bean > </ beans > |
從配置文件中可以看出,抽象bean 的定義與普通bean 的定義幾乎沒有區別,僅僅增加abstract 屬性為true ,但主程序執行結果卻有顯著的差別。下面的主程序采用AppliactionContext 作為Spring 容器, AppliationContext 默認預初始化所有的singleton bean。其主程序部分如下:
1
2
3
4
5
6
7
|
public class BeanTest { public static void main(String[] args) throws Exception{ ApplicationContext ctx = new FileSysternXmlApplicationContext( "bean.xml" ); } } //主程序部分僅僅實例化了ApplicationContext,在實例化ApplicationContext時,默認實例化singleton bean。 |
程序執行結果如下:
Spring 實例化依賴bean: SteelAxe 實例.. .
容器并沒有實例化chineseTemplate bean ,而忽略了所有聲明為abstract 的beano 如果取消abstract 屬性定義,則程序執行結果如下:
Spring 實例化依賴bean: SteelAxe 實~J...
Spring 實例化主調bean: Chinese 實例.. .
Spring 執行依賴關系注入...
可以看出,抽象bean 是一個bean 模板,容器會忽略抽象bean 定義,因而不會實例化抽象bean。但抽象bean 無須實例化,因此可以沒有class 屬性。如下的配置文件也有效:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<? xml version = "1.0" e口 coding = "gb2312" ?> <!一指定Spring 配置文件的dtd> <!DOCTYPE beans PUBLIC "-/!SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd''> <! -- Spring 配置文件的根元素--> < beans > < bean id = "steelAxe" class = "lee.SteelAxe" /> <!一通過abstract 屬性定義該bean 是抽象bean,抽象bean 沒有指定class 屬性一〉 < bean id = "chineseTemplate" abstract = "true" > <!… 定義依賴注入的屬性一〉 < property name = "axe" > < ref local = "steelAxe" /> </ property > </ bean 〉 </beans> |
注意:抽象bean 不能實例化,既不能通過getBean 獲得抽象bean,也不能讓其他bean 的ref 屬性值指向抽象bean,因而只要企圖實例化抽象bean,都將導致錯誤。
定義子bean
我們把指定了parent 屬性值的bean 稱為子bean; parent 指向子bean 的模板,稱為父bean 。子bean 可以從父bean 繼承實現類、構造器參數及屬性值,也可以增加新的值。如果指定了init-method , destroy-method 和factory-method 的屬性,則它們會覆蓋父bean的定義。子bean 無法從父bean 繼承如下屬性: depends-on, autowire, dependency-check,singleton, lazy-init。這些屬性將從子bean 定義中獲得,或采用默認值。通過設置parent 屬性來定義子bean , parent 屬性值為父bean id。修改上面的配置文件如下,增加了子bean 定義:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<? xml version = "1.0" encoding = "gb2312" ?> <!一指定Spring 配置文件的dtd> < lDOCTYPE beans PUBL工C "-//SPRING//DTD BEAN//EN" ''http://www.springframework.org/dtd/spring-beans.dtd''> <!-- Spring 配置文件的根元素一〉 <beans> <bean id="steelAxe" class="lee.SteelAxe"/> <!一通過abstract 屬性定義該bean 是抽象bean--> < bean id = "chineseTemplate" class = "lee.Chinese" abstract = "true" > <!-- 定義依賴注入的屬性一〉 < property name = "axe" > < ref local = "steelAxe" /> </ property > </ bean > <!一通過parent 屬性定義子bean ? < bean id = "chinese" parent = "chineseTemplate" /> </ beans > |
子bean 與普通bean 的定義并沒有太大區別,僅僅增加了parent 屬性。子bean 可以沒有class 屬性,若父bean 定義中有class 屬性,則子bean 定義中可省略其class 屬性,但子bean 將采用與父bean 相同的實現類。
測試程序修改如下:
1
2
3
4
5
6
7
8
|
public class BeanTest { public static void main(String[] args) throws Exception{ ApplicationContext ctx = new FileSysternXmlApplicationContext( "bean.xml" ); Person p = (Person)ctx.getBean( "chinese" ); p.useAxe(); } } |
程序執行結果如下:
Spring 實例化依賴bean: Stee1Axe 實例.. .
Spring實例化主調bean: Chinese 實例.. .
spring 執行依賴關系注入...
鋼斧砍柴真快
另外,子bean 從父bean 定義繼承了實現類并依賴bean 。但子bean 也可覆蓋父bean的定義,看如下的配置文件:
1
2
3
4
5
6
7
8
9
10
11
|
//Axe 的實現類StoneAxe如下: public class StoneAxe implements Axe //默認構造器 public StoneAxe(){ System.out.println("Spring實例化依賴bean: StoneAxe實例.. ."); } //實現Axe 接口的chop 方法 public String chop(){ return "石斧砍柴好慢"; } } |
Chinese子類如下:
1
2
3
4
5
6
7
|
public class Shanghai extends Chinese { public void show() { System.out.println( "子Bean ,中國的上海" ); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<? xm1 version = "1.0" encoding = "gb2312" ?> <! 指定Spring 配置文件的dtd> < lDOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" ''http://www.springframework.org/dtd/spring-beans.dtd''> <! -- Spring 配置文件的根元素一〉 < beans > < bean id = "steelAxe" class = "lee.SteelAxe" /> < bean id = "stoneAxe" class = "lee.StoneAxe" /> <!一通過abstract 屬性定義該bean 是抽象bean--> < bean id = "chineseTemplate" class = "lee.Chinese" abstract = "true" > < property name = "axe" > < ref local = "steelAxe" /> </ property > </ bean > <!一通過parent 屬性定義子bean--> < bean id = "shanghai" parent = "chineseTemplate" > <!一覆蓋父bean 的依賴定義…〉 < property name = "axe" > < ref local = "stoneAxe" /> </ property > </ bean > </ beans > |
此時,子bean 的依賴不再是父bean 定義的依賴了。注意,這個時候的父類lee.Chinese 不能是抽象類,(說明下:有abstract="true")不一定說明這個類一定是個抽象類,不是抽象類同樣可以在Spring里定義為抽象Bean,如果你的Class是抽象類,那這個時候就不能用父Bean的Class,一定要在子Bean中定義Class來初始化這個子Bean)
測試程序修改如下:
1
2
3
4
5
6
7
8
|
public class BeanTest { public static void main(String[] args) throws Exception{ ApplicationContext ctx = new FileSysternXmlApplicationContext( "bean.xml" ); Person p = (Person)ctx.getBean( "shanghai" ); p.useAxe(); } } |
按上面的測試程序執行結果如下:
Spring 實例化依賴bean: SteelAxe 實例.. .
spring 實例化依賴bean: StoneAxe 實例.. .
Spring 實例化主調bean: Chinese 實例.. .
Spring 執行依賴關系注入...
石斧砍柴好慢
注意:上例中的子bean 定義都沒有class 屬性,因為父bean 定義中已有class 屬性,子bean 的class 屬性可從父bean 定義中繼承,但需要注意的是從父Bean繼承Class時,父Bean一定不能是抽象類,因為抽象類不能創建實例;如果父bean 定義中也沒有指定class 屬性,則子bean 定義中必須指定class 屬性,否則會出錯;如果父bean 定義指定了class 屬性,子bean 定義也指定了class 屬性,則子bean 將定義的class 屬性覆蓋父bean 定義的class屬性。
Spring 中bean的繼承和Java中的繼承截然不同,前者是實例與實例之間的參數的延續,后者是一般到特殊的細化,前者是對象和對象之間的關系,后者是類和類之間的關系。
a.Spring中的子bean和父bean可以是不同的類型,但是Java中的繼承,子類是一種特殊的父類;
b.Spring中的bean的繼承是實例之間的關系,主要表現在參數的延續,而Java中的繼承是類與類之間的關系,主要體現在方法和屬性的延續。
c.Spring中子bean不可以作為父bean使用,不具備多態性,Java中的子類實例完全可以當作父類實例使用。
總結
本文有關Spring中bean的繼承與抽象代碼示例的內容就到這里,希望對大家有所幫助。有興趣的朋友可以參閱本站其他專題,精彩不斷。感謝大家對本站的支持!
原文鏈接:http://langgufu.iteye.com/blog/1911615