spring裝配bean的3種方式總結(jié)
前言
這段時(shí)間在學(xué)習(xí)Spring,依賴(lài)注入DI和面向切面編程AOP是Spring框架最核心的部分。這次主要是總結(jié)依賴(lài)注入的bean的裝配方式。
什么是依賴(lài)注入呢?也可以稱(chēng)為控制反轉(zhuǎn),簡(jiǎn)單的來(lái)說(shuō),一般完成稍微復(fù)雜的業(yè)務(wù)邏輯,可能需要多個(gè)類(lèi),會(huì)出現(xiàn)有些類(lèi)要引用其他類(lèi)的實(shí)例,也可以稱(chēng)為依賴(lài)其他類(lèi)。傳統(tǒng)的方法就是直接引用那個(gè)類(lèi)對(duì)象作為自己的一個(gè)屬性,但如果我們每次創(chuàng)建這個(gè)類(lèi)的對(duì)象時(shí),都會(huì)創(chuàng)建依賴(lài)的類(lèi)的對(duì)象,還有如果那個(gè)類(lèi)將來(lái)可能不用了,還需要到這個(gè)類(lèi)去刪除這個(gè)對(duì)象,那破壞了代碼的復(fù)用性和導(dǎo)致高度耦合!
依賴(lài)注入的出現(xiàn)可以很好地解決這個(gè)問(wèn)題,依賴(lài)注入就是由系統(tǒng)負(fù)責(zé)協(xié)調(diào)類(lèi)的依賴(lài)對(duì)象的創(chuàng)建,我們無(wú)需自己去顯示的創(chuàng)建依賴(lài)對(duì)象,而是由系統(tǒng)給我們注入這個(gè)對(duì)象,系統(tǒng)控制了這個(gè)對(duì)象的創(chuàng)建,也稱(chēng)為控制反轉(zhuǎn)。
Spring給我們注入對(duì)象有三種方式:
- 隱式的bean掃描發(fā)現(xiàn)機(jī)制和自動(dòng)裝配
- 在java中進(jìn)行顯示配置
- 在XML中進(jìn)行顯示配置
第一種:
spring從兩個(gè)角度實(shí)現(xiàn)自動(dòng)化裝配:組件掃描和自動(dòng)裝配。
當(dāng)對(duì)一個(gè)類(lèi)標(biāo)注@Component注解時(shí),表明該類(lèi)會(huì)作為組件類(lèi),spring將為這個(gè)類(lèi)創(chuàng)建bean。當(dāng)在應(yīng)用文中引用這個(gè)bean,spring會(huì)自動(dòng)掃描事先指定的包查找這個(gè) bean。但spring默認(rèn)是不啟用組件掃描的,可以在XML中配置加上<context:component-scan base-package="xx"/>
。還有一種方法:在新建一個(gè)配置類(lèi),類(lèi)中可以什么不用寫(xiě),在配置類(lèi)上加上@ComponentScan注解,spring會(huì)自動(dòng)掃描改配置類(lèi)所在的包,一般應(yīng)該傾向xml配置。下面是一個(gè)bbs論壇系統(tǒng)用戶(hù)發(fā)帖的功能小例子:
package bbs.dao; @Component public interface Postdao { /* *用戶(hù)發(fā)帖 ,post表添加帖子信息 */ public int addpost(@Param("title") String title,@Param("content") String content,@Param("userid") int userid); } package bbs.dao; @Component public interface Userdao { /* * 用戶(hù)發(fā)帖后,user表將用戶(hù)發(fā)帖數(shù)加一 */ public int addpost(int userid); }
再在bbs.service包中創(chuàng)建一個(gè)postservice接口及其實(shí)現(xiàn)類(lèi),依賴(lài)Postdao和Userdao。
package bbs.service; public interface PostService { /* 用戶(hù)發(fā)帖后,先添加帖子信息再更新用戶(hù)發(fā)帖數(shù)量 */ public void addpost(String title,String content,int userid); } package bbs.service; @Component public class PostserviceImpl implements PostService { private Postdao postdao; private Userdao userdao; // @Autowired // public void setPostdao(Postdao postdao) // { // this.postdao=postdao; // } // // @Autowired // public void setUserdao(Userdao userdao) // { // this.userdao=userdao; // } @Autowired public PostserviceImpl(Postdao postdao,Userdao userdao) { this.userdao=userdao; this.postdao=postdao; } public void addpost(String title, String content, int userid) { int i=postdao.addpost(title, content, userid); int j=userdao.addpost(userid); if(i==1&j==1) System.out.println("發(fā)帖成功"); else System.out.println("發(fā)帖失敗"); } }
@Component在接口實(shí)現(xiàn)上注解就可以,但發(fā)現(xiàn)在userdao、postdao接口也加上了,其實(shí)可以去掉,因?yàn)槲也捎胢ybatis在xml中配置數(shù)據(jù)庫(kù)的操作,動(dòng)態(tài)實(shí)現(xiàn)dao接口。等下會(huì)提到。上面代碼出現(xiàn)的@Autowired注解實(shí)現(xiàn)bean自動(dòng)裝配,會(huì)在spring應(yīng)用上下文中的組件類(lèi)尋找需求的bean。一般有兩種裝配方式:構(gòu)造器和Setter方法(其他方法名也行,只要能夠使注入的bean成為這個(gè)類(lèi)的屬性就行)
也可能出現(xiàn)spring沒(méi)有查找到匹配的bean會(huì)拋出異常,在@Autowired加上required=false
,如果沒(méi)有匹配的bean時(shí),spring會(huì)使這個(gè)bean處于未裝配的狀態(tài),沒(méi)有裝配成功。還有可能會(huì)出現(xiàn)相同名字的bean有很多個(gè),會(huì)產(chǎn)生歧義,一般在組件類(lèi)上添加注解@Qualifier()
括號(hào)寫(xiě)這個(gè)bean的id,在注入時(shí)也加上@Qualifier()
,寫(xiě)上bean的id。像下面:
@Component @Qualifier("postdao") public interface Postdao{ . . . . } @Component @Qualifier("userdao") public interface Userdao{ . . . . } @Autowired @Qualifier("usedao") public void setUserdao(Userdao userdao) {. . . } @Autowired @Qualifier("postdao") public void setUserdao(Postdao postdao) {. . . }
由于java不允許在同一個(gè)條目上重復(fù)出現(xiàn)相同類(lèi)型的多個(gè)注解,所有注入采用set方式。但是其實(shí)可以創(chuàng)建自定義的限定符注解。這里就不介紹啦。
第二種:
通過(guò)java代碼裝配bean
一般通過(guò)組件掃描和自動(dòng)裝配方式就比較方便了,但如果由于需求我們要使用第三方的庫(kù)的類(lèi),在這種情況沒(méi)有辦法到第三方庫(kù)中去給類(lèi)加注解,就不能使用第一種方法了。這時(shí)得采用顯示裝配,可以采用java代碼或xml顯示裝配bean。使用java代碼,先新建一個(gè)配置類(lèi)JavaConfig,里面都是配置所需的bean,不應(yīng)該有業(yè)務(wù)邏輯代碼,所以單獨(dú)建一個(gè)類(lèi)。
@Configuration @ContextConfiguration(locations = {"classpath:spring/spring-dao.xml","classpath:scan.xml"}) public class bbsConfig{ private Postdao postdao; private Userdao userdao; @Bean(name="postservice") public PostService getPost() { return new PostserviceImpl(postdao,userdao); }
在對(duì)PostService的bean注入時(shí),同時(shí)又依賴(lài)了兩個(gè)bean,postdao和userdao。直接引用beanID就可以,spring會(huì)自動(dòng)地從容器中獲取這些bean,只要他們的配置是正確的就行。這個(gè)例子中userdao、postdao是Mybatis配置自動(dòng)掃描將dao接口生成代理注入到spring的,其實(shí)也算是xml裝配bean。可參考這篇文章,寫(xiě)的挺清楚的。 http://www.dbjr.com.cn/article/157618.htm
這里如果再聲明一個(gè)bean,返回的仍是postserviceImpl對(duì)象,和之前的那個(gè)bean完全一樣,是同一個(gè)實(shí)例。一般spring@bean如果是同一個(gè)beanID,默認(rèn)返回的是一個(gè)單例bean,注入的是同一個(gè)實(shí)例。如果修改其中一個(gè)會(huì)都改變的。
不過(guò)在這里要注意進(jìn)行測(cè)試時(shí),由于spring的單元測(cè)試和springIoc容器是完全獨(dú)立的,postdao和userdao注入檢測(cè)時(shí)是使用locations加載xml文件,而postservice使用classes加載config類(lèi)的,但是兩個(gè)不能同時(shí)混用在@ContextConfiguration中。所以非要都測(cè)試的話(huà),就分開(kāi)測(cè)試吧。
第三種:
在XML中裝配bean
<?xml version="1.0" encoding="UTF-8" ?> <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 http://www.springframework.org/schema/context"> <import resource="spring/spring-dao.xml"/> <bean id="postservice" class="com.bbs.service.impl.PostserviceImpl"> <constructor-arg ref="postdao"/> <constructor-arg ref="userdao"/> </bean> </beans>
配置postservice的bean時(shí)需要引入兩個(gè)bean,postdao和userdao,放到constructor-arg的標(biāo)簽中,ref指的是依賴(lài)的bean的ID。如果是在javaConfig中配置的,就寫(xiě)@Bean的內(nèi)容。如果是@Component就寫(xiě)@Qualifier的內(nèi)容。這里是引入的是動(dòng)態(tài)實(shí)現(xiàn)的dao接口的bean,是在spring-dao.xml中配置的,引入這個(gè)配置文件就可以自動(dòng)獲得beanID。
混合使用三種裝配:
1.在類(lèi)上可以使用@ import(bbsConfig.class)
組合其他java注解
2.在類(lèi)上使用@ imortResource("classpath:spring-dao.xml")
組合其他xml注解
3.在類(lèi)上可以使用@ContenxtConfiguration
包含class或者xml
4.在xml中可以用<import resource="spring-dao.xml">
引入xml注解,也可以使用<bean class="com.bbs.dao.Userdao">
引入java注解
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
- spring如何使用xml裝配bean
- 基于XML配置Spring的自動(dòng)裝配過(guò)程解析
- Spring裝配Bean教程之XML安裝配置bean詳解
- sersync2 完全安裝配置說(shuō)明(二) 可選功能與xml高級(jí)配置
- Spring注解實(shí)現(xiàn)Bean自動(dòng)裝配示例詳解
- Spring IOC裝配Bean過(guò)程解析
- Spring自動(dòng)裝配Bean實(shí)現(xiàn)過(guò)程詳解
- spring boot中的條件裝配bean的實(shí)現(xiàn)
- 在Spring中自動(dòng)裝配Bean的屬性
- spring在IoC容器中裝配Bean詳解
- 詳解SpringBean基于XML的裝配
相關(guān)文章
Java數(shù)據(jù)結(jié)構(gòu)之順序表的實(shí)現(xiàn)
線(xiàn)性表(linear?list)是n個(gè)具有相同特性的數(shù)據(jù)元素的有限序列。順序表是常見(jiàn)的線(xiàn)性表之一,本文將詳細(xì)講講順序表的原理與實(shí)現(xiàn),需要的可以參考一下2022-08-08Java實(shí)現(xiàn)批量修改文件名和重命名的方法
這篇文章主要介紹了Java實(shí)現(xiàn)批量修改文件名和重命名的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09springboot實(shí)現(xiàn)多模塊項(xiàng)目添加一新模塊
這篇文章主要介紹了springboot實(shí)現(xiàn)多模塊項(xiàng)目添加一新模塊,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02SpringBoot操作Mongodb的實(shí)現(xiàn)示例
本文主要介紹了SpringBoot操作Mongodb的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06@Resource和@Autowired兩個(gè)注解的區(qū)別及說(shuō)明
這篇文章主要介紹了@Resource和@Autowired兩個(gè)注解的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06java 如何把byte轉(zhuǎn)化為KB、MB、GB的方法
這篇文章主要介紹了java 如何把byte轉(zhuǎn)化為KB、MB、GB的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10關(guān)于Spring啟動(dòng)流程及Bean生命周期梳理
這篇文章主要介紹了關(guān)于Spring啟動(dòng)流程及Bean生命周期梳理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11idea熱部署插件jrebel正式版及破解版安裝詳細(xì)圖文教程
這篇文章主要介紹了idea熱部署插件jrebel正式版及破解版安裝詳細(xì)教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12SpringBoot中的6種API請(qǐng)求參數(shù)讀取方式總結(jié)
使用Spring Boot開(kāi)發(fā)API的時(shí)候,讀取請(qǐng)求參數(shù)是服務(wù)端編碼中最基本的一項(xiàng)操作,Spring Boot中也提供了多種機(jī)制來(lái)滿(mǎn)足不同的API設(shè)計(jì)要求,通過(guò)本文,為大家總結(jié)6種常用的請(qǐng)求參數(shù)讀取方式,需要的朋友可以參考下2024-07-07