淺談Spring裝配Bean之組件掃描和自動(dòng)裝配
Spring從兩個(gè)角度來(lái)實(shí)現(xiàn)自動(dòng)化裝配:
- 組件掃描:Spring會(huì)自動(dòng)發(fā)現(xiàn)應(yīng)用上下文中所創(chuàng)建的bean。
- 自動(dòng)裝配:Spring自動(dòng)滿(mǎn)足bean之間的依賴(lài)。
案例:音響系統(tǒng)的組件。首先為CD創(chuàng)建CompactDisc接口及實(shí)現(xiàn)類(lèi),Spring會(huì)發(fā)現(xiàn)它并將其創(chuàng)建為一個(gè)bean。然后,會(huì)創(chuàng)建一個(gè)CDPlayer類(lèi),讓Spring發(fā)現(xiàn)它,并將CompactDisc bean注入進(jìn)來(lái)。
創(chuàng)建CompactDisc接口:
package soundsystem; public interface CompactDisc { void play(); }
實(shí)現(xiàn)CompactDisc接口:
package soundsystem; import org.springframework.stereotype.Component; @Component public class SgtPeppers implements CompactDisc { private String title = "Sgt. Pepper's Lonely Hearts Club Band"; private String artist = "The Beatles"; public void play() { System.out.println("Playing " + title + " by " + artist); } }
在SgtPeppers類(lèi)上使用了 @Component注解,這個(gè)注解表明該類(lèi)會(huì)作為組件類(lèi),并告知Spring要為這個(gè)類(lèi)創(chuàng)建bean,不需要顯示配置SgtPeppers bean。
不過(guò)組件掃描默認(rèn)是不開(kāi)啟的。我們需要顯示配置一下Spring,從而命令Spring去尋找?guī)в?@Component注解的類(lèi),并創(chuàng)建bean。
顯示配置Spring包括Java和XML兩種方式,通過(guò)Java啟用組件掃描:
package soundsystem; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan public class CDPlayerConfig { }
注意,類(lèi)CDPlayerConfig通過(guò)Java代碼定義了Spring的裝配規(guī)則,但是可以看出并沒(méi)有顯示地聲明任何bean,只不過(guò)它使用了 @ComponentScan注解,這個(gè)注解能夠在Spring中啟用組件掃描。
如果沒(méi)有其他配置的話(huà),@ComponentScan默認(rèn)會(huì)掃描與配置類(lèi)相同的包。因?yàn)镃DPlayerConfig位于sound system包中,因此Spring默認(rèn)將會(huì)掃描這個(gè)包以及這個(gè)包下的所有子包,查找所有帶有 @Component注解的類(lèi)。這樣的話(huà),SgtPeppers類(lèi)就會(huì)被自動(dòng)創(chuàng)建一個(gè)bean。
通過(guò)XML啟用組件掃描
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; xmlns:context="http://www.springframework.org/schema/context"; xmlns:c="http://www.springframework.org/schema/c"; xmlns:p="http://www.springframework.org/schema/p"; xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd">; <context:component-scan base-package="soundsystem" /> </beans>
測(cè)試組件掃描能夠發(fā)現(xiàn)CompactDisc:
package soundsystem; import static org.junit.Assert.*; import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.StandardOutputStreamLog; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=CDPlayerConfig.class) public class CDPlayerTest { @Rule public final StandardOutputStreamLog log = new StandardOutputStreamLog(); @Autowired private CompactDisc cd; @Test public void cdShouldNotBeNull() { assertNotNull(cd); } }
CDPlayerTest使用了Spring的SpringJUnit4ClassRunner,以便在測(cè)試開(kāi)始的時(shí)候自動(dòng)創(chuàng)建Spring的應(yīng)用上下文。注解ContextConfiguration會(huì)告訴它需要在CDPlayerConfig類(lèi)中加載配置。因?yàn)镃DPlayerConfig類(lèi)中包含了 @ComponentScan,因此最終的應(yīng)用上下文應(yīng)該包含CompactDisc bean。
測(cè)試方法斷言cd屬性部位null。如果不為null。就意味著Spring能發(fā)現(xiàn)CompactDisc類(lèi),并自動(dòng)在Spring上下文中創(chuàng)建為bean并注入到測(cè)試代碼中。
為組件掃描的bean命名
Spring應(yīng)用上下文中所有的bean都會(huì)給定一個(gè)ID。默認(rèn)bean命名為類(lèi)名的第一個(gè)字母變?yōu)樾?xiě),上面的SgtPeppers bean指定的ID為sgtPeppers。
如果想要指定bean ID,可以將ID值傳遞給 @Component注解。如下:
@Component("lonelyHeartsClub") public class SgtPeppers implements CompactDisc { }
設(shè)置組件掃描的基礎(chǔ)包
@Component注解沒(méi)有設(shè)置任何屬性的情況下,按照默認(rèn)規(guī)則,Spring會(huì)以配置類(lèi)所在的包作為基礎(chǔ)包來(lái)掃描組件。但是如果想掃描不同的包,需要做的就是@Component的value屬性中指名包的名稱(chēng):
@Configuration @ComponentScan("soundsystem") public class CDPlayerConfig { }
如果想更加清晰的表明設(shè)置的基礎(chǔ)包,可以通過(guò)設(shè)置basePackages屬性:
@Configuration @ComponentScan(basePackages="soundsystem") public class CDPlayerConfig { }
同時(shí)basePackages支持多個(gè)基礎(chǔ)包的設(shè)置,屬性設(shè)置為數(shù)組即可:
@Configuration @ComponentScan(basePackages={"soundsystem", "voice"}) public class CDPlayerConfig { }
另外還提供一種方法,可以指定包中所含的類(lèi)或接口:
@Configuration @ComponentScan(basePackegeClasses={CDPlayer.class, DVDPlayer.class}) public class CDPlayerConfig { }
通過(guò)為bean添加注解實(shí)現(xiàn)自動(dòng)裝配
自動(dòng)裝配就是讓Spring自動(dòng)滿(mǎn)足bean依賴(lài)的一種方式,在滿(mǎn)足依賴(lài)的過(guò)程中,會(huì)在Spring的上下文中尋找匹配一個(gè)bean需求的其他bean。為了聲明要進(jìn)行自動(dòng)裝配,我們可以借助Spring的 @Autowried注解。
比如說(shuō)CDPlayer類(lèi),它在構(gòu)造器上添加了 @Autowried注解,這表明當(dāng)創(chuàng)建CDPlayer bean的時(shí)候,會(huì)通過(guò)這個(gè)構(gòu)造器來(lái)進(jìn)行實(shí)例化并且會(huì)傳入一個(gè)可設(shè)置給CompactDisc類(lèi)型的bean。
package soundsystem; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class CDPlayer implements MediaPlayer { private CompactDisc cd; @Autowired public CDPlayer(CompactDisc cd) { this.cd = cd; } public void play() { cd.play(); } } @Autowried注解不僅能夠用在構(gòu)造器上,還能用在Setter方法上。 @Autowired public void setCompactDisc(CompactDisc cd) { this.cd = cd; }
事實(shí)上,@Autowried注解可以用在類(lèi)的任何方法上去引入依賴(lài)的bean,Spring都會(huì)嘗試滿(mǎn)足方法參數(shù)上所聲明的依賴(lài)。
如果沒(méi)有匹配的bean,那么在應(yīng)用上下文創(chuàng)建的時(shí)候,Spring會(huì)拋出一個(gè)異常。為了避免出現(xiàn)異常,可以將 @Autowried的required屬性設(shè)置為false:
@Autowired(required=false) public CDPlayer(CompactDisc cd) { this.cd = cd; }
設(shè)置以后,會(huì)嘗試自動(dòng)裝配,但是如果沒(méi)有匹配的bean,Spring默認(rèn)會(huì)處于未裝配的狀態(tài)。但是把required設(shè)置為false時(shí),需要謹(jǐn)慎對(duì)待,如果代碼中沒(méi)有進(jìn)行null檢查的話(huà),建議不使用,不然就會(huì)出現(xiàn)NullPointerException異常。
驗(yàn)證自動(dòng)裝配
前面我們的CDPlayerTest測(cè)試類(lèi),實(shí)現(xiàn)了自動(dòng)裝配CompactDisc,現(xiàn)在我們借助CDPlayer bean播放CD,表現(xiàn)出依賴(lài)的自動(dòng)裝配:
package soundsystem; import static org.junit.Assert.*; import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.StandardOutputStreamLog; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=CDPlayerConfig.class) public class CDPlayerTest { @Rule public final StandardOutputStreamLog log = new StandardOutputStreamLog(); @Autowired private MediaPlayer player; @Autowired private CompactDisc cd; @Test public void cdShouldNotBeNull() { assertNotNull(cd); } @Test public void play() { player.play(); assertEquals( "Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles\n", log.getLog()); } }
現(xiàn)在除了注入CompactDisc,還將CDPlayer bean注入到測(cè)試代碼的player成員變量中。
總結(jié)一下,自動(dòng)裝配bean的過(guò)程:
一、把需要被掃描的類(lèi),添加 @Component注解,使它能夠被Spring自動(dòng)發(fā)現(xiàn)。
二、通過(guò)顯示的設(shè)置Java代碼 @ComponentScan注解或XML配置,讓Spring開(kāi)啟組件掃描,并將掃描的結(jié)果類(lèi)創(chuàng)建bean。
三、@Autowried注解能偶實(shí)現(xiàn)bean的自動(dòng)裝配,實(shí)現(xiàn)依賴(lài)注入。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot解決數(shù)據(jù)庫(kù)時(shí)間和返回時(shí)間格式不一致的問(wèn)題
這篇文章主要介紹了SpringBoot解決數(shù)據(jù)庫(kù)時(shí)間和返回時(shí)間格式不一致的問(wèn)題,文章通過(guò)代碼示例和圖文結(jié)合的方式講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)和工作有一定的幫助,需要的朋友可以參考下2024-03-03java開(kāi)發(fā)之鬧鐘的實(shí)現(xiàn)代碼
本篇文章介紹了,在java中鬧鐘的實(shí)現(xiàn)代碼。需要的朋友參考下2013-05-05MyBatis-Plus樂(lè)觀鎖插件的用法小結(jié)
樂(lè)觀鎖很樂(lè)觀,對(duì)任何事情都保持著一個(gè)樂(lè)觀的態(tài)度,認(rèn)為別人不會(huì)修改數(shù)據(jù),所以不會(huì)上鎖,只是在更新數(shù)據(jù)的時(shí)候,去判斷這條數(shù)據(jù)有沒(méi)有被別人修改過(guò),這篇文章主要介紹了MyBatis-Plus樂(lè)觀鎖插件的用法,需要的朋友可以參考下2022-08-08Java Eclipse中實(shí)現(xiàn)快速替換變量
這篇文章主要介紹了Java Eclipse中實(shí)現(xiàn)快速替換變量,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09selenium高效應(yīng)對(duì)Web頁(yè)面元素刷新的實(shí)例講解
今天小編就為大家分享一篇selenium高效應(yīng)對(duì)Web頁(yè)面元素刷新的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05Java面向?qū)ο蟪绦蛟O(shè)計(jì):類(lèi)的定義,靜態(tài)變量,成員變量,構(gòu)造函數(shù),封裝與私有,this概念與用法詳解
這篇文章主要介紹了Java面向?qū)ο箢?lèi)的定義,靜態(tài)變量,成員變量,構(gòu)造函數(shù),封裝與私有,this概念與用法,較為詳細(xì)的分析了Java類(lèi)的定義,靜態(tài)變量,成員變量,構(gòu)造函數(shù),封裝,私有等相關(guān)原理、用法及操作注意事項(xiàng),需要的朋友可以參考下2020-04-04