Spring中bean的繼承與抽象代碼示例
我們?cè)趹?yīng)用Spring時(shí),在一般的設(shè)計(jì)時(shí),肯定要用的抽象類。那在Spring中怎么樣配置這些抽象Bean呢。請(qǐng)看下面:
如果兩個(gè)bean 之間的配置信息非常相似,可利用繼承來(lái)減少重復(fù)配置工作。
繼承是指子bean 定義可從父bean 定義繼承部分配置信息,也可覆蓋特定的配置信息,或者添加一些配置。使用繼承配置可以節(jié)省很多的配置工作。在實(shí)際應(yīng)用中,通用配置會(huì)被配置成模板,可供子bean 繼承。
使用abstract 屬性
正如前面所介紹的,通用的配置會(huì)被配置成模板,而模板不需要實(shí)例化,僅僅作為子bean 定義的模板使用。而ApplicationContext 默認(rèn)預(yù)初始化所有的singleton bean 。使用abstract 屬性,可以阻止模板bean 被預(yù)初始化。abstract 屬性為true 的bean 稱為抽象bean ,容器會(huì)忽略所有的抽象bean 定義,預(yù)初始化時(shí)不初始化抽象bean。如果沒(méi)有定義abstract 屬性,該屬性默認(rèn)為false 。如下配置文件定義了一個(gè)抽象bean ,該抽象bean 作為模板使用:
public class SteelAxe implements Axe { //count 是個(gè)狀態(tài)值,每次執(zhí)行chop 方法該值增加1 private int count = 0; public SteelAxe(){ System.out.println("Spring實(shí)例化依賴bean: SteelAxe 實(shí)例.. ."); } //測(cè)試用方法 public String chop(){ return "鋼斧砍柴真快" + ++count; } } public class Chinese implements Person //面向Axe 接口編程,而不是具體的實(shí)現(xiàn)類 private Axe axe; //默認(rèn)的構(gòu)造器 public Chinese(){ System.out.println("Spring實(shí)例化主調(diào)bean: Chinese 實(shí)例... "); } //設(shè)值注入所需的setter 方法 public void setAxe( Axe axe){ System.out.pr工ntln (" Spring 執(zhí)行依賴關(guān)系注入..."); this.axe = axe; } //實(shí)現(xiàn)Person 接口的useAxe 方法 public void useAxe(){ System.out.println(axe.chop()); } }
<?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"/> <!… 通過(guò)abstract 屬性定義該bean 是抽象bean--> <bean id="chineseTemplate" class="lee.Chinese" abstract="true"> <!一定義依賴注入的屬性一〉 <property name="axe"> <ref local="steelAxe"/> </property> </bean> </beans>
從配置文件中可以看出,抽象bean 的定義與普通bean 的定義幾乎沒(méi)有區(qū)別,僅僅增加abstract 屬性為true ,但主程序執(zhí)行結(jié)果卻有顯著的差別。下面的主程序采用AppliactionContext 作為Spring 容器, AppliationContext 默認(rèn)預(yù)初始化所有的singleton bean。其主程序部分如下:
public class BeanTest { public static void main(String[] args)throws Exception{ ApplicationContext ctx = new FileSysternXmlApplicationContext("bean.xml"); } } //主程序部分僅僅實(shí)例化了ApplicationContext,在實(shí)例化ApplicationContext時(shí),默認(rèn)實(shí)例化singleton bean。
程序執(zhí)行結(jié)果如下:
Spring 實(shí)例化依賴bean: SteelAxe 實(shí)例.. .
容器并沒(méi)有實(shí)例化chineseTemplate bean ,而忽略了所有聲明為abstract 的beano 如果取消abstract 屬性定義,則程序執(zhí)行結(jié)果如下:
Spring 實(shí)例化依賴bean: SteelAxe 實(shí)~J...
Spring 實(shí)例化主調(diào)bean: Chinese 實(shí)例.. .
Spring 執(zhí)行依賴關(guān)系注入...
可以看出,抽象bean 是一個(gè)bean 模板,容器會(huì)忽略抽象bean 定義,因而不會(huì)實(shí)例化抽象bean。但抽象bean 無(wú)須實(shí)例化,因此可以沒(méi)有class 屬性。如下的配置文件也有效:
<?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"/> <!一通過(guò)abstract 屬性定義該bean 是抽象bean,抽象bean 沒(méi)有指定class 屬性一〉 <bean id="chineseTemplate" abstract="true"> <!… 定義依賴注入的屬性一〉 <property name="axe"> <ref local="steelAxe"/> </property> </bean〉 </beans>
注意:抽象bean 不能實(shí)例化,既不能通過(guò)getBean 獲得抽象bean,也不能讓其他bean 的ref 屬性值指向抽象bean,因而只要企圖實(shí)例化抽象bean,都將導(dǎo)致錯(cuò)誤。
定義子bean
我們把指定了parent 屬性值的bean 稱為子bean; parent 指向子bean 的模板,稱為父bean 。子bean 可以從父bean 繼承實(shí)現(xiàn)類、構(gòu)造器參數(shù)及屬性值,也可以增加新的值。如果指定了init-method , destroy-method 和factory-method 的屬性,則它們會(huì)覆蓋父bean的定義。子bean 無(wú)法從父bean 繼承如下屬性: depends-on, autowire, dependency-check,singleton, lazy-init。這些屬性將從子bean 定義中獲得,或采用默認(rèn)值。通過(guò)設(shè)置parent 屬性來(lái)定義子bean , parent 屬性值為父bean id。修改上面的配置文件如下,增加了子bean 定義:
<?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"/> <!一通過(guò)abstract 屬性定義該bean 是抽象bean--> <bean id="chineseTemplate" class="lee.Chinese" abstract="true"> <!-- 定義依賴注入的屬性一〉 <property name="axe"> <ref local="steelAxe"/> </property> </bean> <!一通過(guò)parent 屬性定義子bean ? <bean id="chinese" parent="chineseTemplate"/> </beans>
子bean 與普通bean 的定義并沒(méi)有太大區(qū)別,僅僅增加了parent 屬性。子bean 可以沒(méi)有class 屬性,若父bean 定義中有class 屬性,則子bean 定義中可省略其class 屬性,但子bean 將采用與父bean 相同的實(shí)現(xiàn)類。
測(cè)試程序修改如下:
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(); } }
程序執(zhí)行結(jié)果如下:
Spring 實(shí)例化依賴bean: Stee1Axe 實(shí)例.. .
Spring實(shí)例化主調(diào)bean: Chinese 實(shí)例.. .
spring 執(zhí)行依賴關(guān)系注入...
鋼斧砍柴真快
另外,子bean 從父bean 定義繼承了實(shí)現(xiàn)類并依賴bean 。但子bean 也可覆蓋父bean的定義,看如下的配置文件:
//Axe 的實(shí)現(xiàn)類StoneAxe如下: public class StoneAxe implements Axe //默認(rèn)構(gòu)造器 public StoneAxe(){ System.out.println("Spring實(shí)例化依賴bean: StoneAxe實(shí)例.. ."); } //實(shí)現(xiàn)Axe 接口的chop 方法 public String chop(){ return "石斧砍柴好慢"; } }
Chinese子類如下:
public class Shanghai extends Chinese { public void show() { System.out.println("子Bean ,中國(guó)的上海"); } }
<?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"/> <!一通過(guò)abstract 屬性定義該bean 是抽象bean--> <bean id="chineseTemplate" class="lee.Chinese" abstract="true"> <property name="axe"> <ref local="steelAxe"/> </property> </bean> <!一通過(guò)parent 屬性定義子bean--> <bean id="shanghai" parent="chineseTemplate"> <!一覆蓋父bean 的依賴定義…〉 <property name="axe"> <ref local="stoneAxe"/> </property> </bean> </beans>
此時(shí),子bean 的依賴不再是父bean 定義的依賴了。注意,這個(gè)時(shí)候的父類lee.Chinese 不能是抽象類,(說(shuō)明下:有abstract="true")不一定說(shuō)明這個(gè)類一定是個(gè)抽象類,不是抽象類同樣可以在Spring里定義為抽象Bean,如果你的Class是抽象類,那這個(gè)時(shí)候就不能用父Bean的Class,一定要在子Bean中定義Class來(lái)初始化這個(gè)子Bean)
測(cè)試程序修改如下:
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(); } }
按上面的測(cè)試程序執(zhí)行結(jié)果如下:
Spring 實(shí)例化依賴bean: SteelAxe 實(shí)例.. .
spring 實(shí)例化依賴bean: StoneAxe 實(shí)例.. .
Spring 實(shí)例化主調(diào)bean: Chinese 實(shí)例.. .
Spring 執(zhí)行依賴關(guān)系注入...
石斧砍柴好慢
注意:上例中的子bean 定義都沒(méi)有class 屬性,因?yàn)楦竍ean 定義中已有class 屬性,子bean 的class 屬性可從父bean 定義中繼承,但需要注意的是從父Bean繼承Class時(shí),父Bean一定不能是抽象類,因?yàn)槌橄箢惒荒軇?chuàng)建實(shí)例;如果父bean 定義中也沒(méi)有指定class 屬性,則子bean 定義中必須指定class 屬性,否則會(huì)出錯(cuò);如果父bean 定義指定了class 屬性,子bean 定義也指定了class 屬性,則子bean 將定義的class 屬性覆蓋父bean 定義的class屬性。
Spring 中bean的繼承和Java中的繼承截然不同,前者是實(shí)例與實(shí)例之間的參數(shù)的延續(xù),后者是一般到特殊的細(xì)化,前者是對(duì)象和對(duì)象之間的關(guān)系,后者是類和類之間的關(guān)系。
a.Spring中的子bean和父bean可以是不同的類型,但是Java中的繼承,子類是一種特殊的父類;
b.Spring中的bean的繼承是實(shí)例之間的關(guān)系,主要表現(xiàn)在參數(shù)的延續(xù),而Java中的繼承是類與類之間的關(guān)系,主要體現(xiàn)在方法和屬性的延續(xù)。
c.Spring中子bean不可以作為父bean使用,不具備多態(tài)性,Java中的子類實(shí)例完全可以當(dāng)作父類實(shí)例使用。
總結(jié)
本文有關(guān)Spring中bean的繼承與抽象代碼示例的內(nèi)容就到這里,希望對(duì)大家有所幫助。有興趣的朋友可以參閱本站其他專題,精彩不斷。感謝大家對(duì)本站的支持!
- 詳解Spring 中如何控制2個(gè)bean中的初始化順序
- Spring @Bean vs @Service注解區(qū)別
- 詳解Spring簡(jiǎn)單容器中的Bean基本加載過(guò)程
- Spring Boot如何動(dòng)態(tài)創(chuàng)建Bean示例代碼
- 詳解Spring中bean的幾種注入方式
- Spring boot將配置屬性注入到bean類中
- Java中Spring獲取bean方法小結(jié)
- Spring中如何動(dòng)態(tài)注入Bean實(shí)例教程
- Spring多種加載Bean方式解析
- Spring實(shí)戰(zhàn)之抽象Bean和子Bean定義與用法示例
相關(guān)文章
Hadoop環(huán)境配置之hive環(huán)境配置詳解
這篇文章主要介紹了Hadoop環(huán)境配置之hive環(huán)境配置,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12Kafka常用命令之kafka-console-consumer.sh解讀
這篇文章主要介紹了Kafka常用命令之kafka-console-consumer.sh解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03Java 對(duì)HashMap進(jìn)行排序的三種常見(jiàn)方法
這篇文章主要介紹了Java 對(duì)HashMap進(jìn)行排序的三種常見(jiàn)方法,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-10-10Java 通過(guò) 二三法 巧解前端數(shù)據(jù)顯示
實(shí)踐來(lái)源于理論,做開(kāi)發(fā)前肯定要先了解相關(guān)的規(guī)則和原理,看到標(biāo)題或許你會(huì)好奇什么是二三法。本篇文章帶你深入了解,需要的朋友可以參考下2021-10-10關(guān)于線程池異步線程中再次獲取線程池資源的問(wèn)題
這篇文章主要介紹了關(guān)于線程池異步線程中再次獲取線程池資源的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08java實(shí)現(xiàn)科學(xué)計(jì)算器的全過(guò)程與代碼
最近編寫(xiě)了一個(gè)功能較全面的科學(xué)計(jì)算器,該計(jì)算器不僅能進(jìn)行加、減、乘、除等混合運(yùn)算,而且能計(jì)算sin、cos、tan、log等函數(shù)的值,還要具有清零、退格、求倒數(shù)、求相反數(shù)等功能,這篇文章主要給大家介紹了關(guān)于java實(shí)現(xiàn)科學(xué)計(jì)算器的相關(guān)資料,需要的朋友可以參考下2022-06-06SpringBoot實(shí)現(xiàn)PPT格式文件上傳并在線預(yù)覽功能
本文介紹SpringBoot實(shí)現(xiàn)PPT格式文件上傳并在線預(yù)覽功能,通過(guò)上傳接口,可在C盤(pán)的tempfile目錄下找到上傳的文件,預(yù)覽時(shí)會(huì)在同級(jí)目錄下創(chuàng)建一個(gè)相同文件名后綴為pdf的文件,每次預(yù)覽會(huì)先查找文件是否存在,存在則直接預(yù)覽,不存在則會(huì)走上面的處理,需要的朋友可以參考下2022-02-02Map映射LinkedHashSet與LinkedHashMap應(yīng)用解析
這篇文章主要為大家介紹了Map映射LinkedHashSet與LinkedHashMap的應(yīng)用解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步2022-03-03淺談MultipartFile中transferTo方法的坑
這篇文章主要介紹了MultipartFile中transferTo方法的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07SpringBoot添加自定義攔截器的實(shí)現(xiàn)代碼
這篇文章主要介紹了SpringBoot添加自定義攔截器的實(shí)現(xiàn)代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09