Spring小記(3):Spring的bean的裝配(基礎(chǔ))

在spring中面哥,對(duì)象無(wú)需自己查找或創(chuàng)建與其所關(guān)聯(lián)的其他對(duì)象,容器負(fù)責(zé)把需要相互協(xié)作的對(duì)象引用賦予各個(gè)對(duì)象,容器的這種創(chuàng)建對(duì)象之間協(xié)作關(guān)系的行為被稱(chēng)為裝配作媚,也被成為依賴(lài)注入(DI),依賴(lài)注入有3種方案可供選用帅刊,如下

1纸泡、在XML中進(jìn)行顯式的配置
2、在Java中進(jìn)行顯式的配置
3赖瞒、隱式的bean發(fā)現(xiàn)機(jī)制和自動(dòng)裝配
隱式的bean發(fā)現(xiàn)機(jī)制和自動(dòng)裝配

看下面一個(gè)實(shí)例
1女揭、創(chuàng)建一個(gè)接口

public interface CompactDisc {
    void play();
}

2蚤假、添加這個(gè)接口的實(shí)現(xiàn),注意我們?cè)陬?lèi)的頭部添加了@Component的注解,表明這個(gè)類(lèi)是一個(gè)組件

@Component
public class SgtPeppers implements CompactDisc {
    private String title = "Sgt. Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";


    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }
}

3吧兔、添加對(duì)這個(gè)組件的配置磷仰,這個(gè)類(lèi)里面什么東西都沒(méi)有,只有類(lèi)的頭部有兩個(gè)注解境蔼,分別為@Configuration和@ComponentScan灶平,其中@ComponentScan注解表明會(huì)對(duì)這個(gè)包中的包含@Component的類(lèi)進(jìn)行掃描

@Configuration
@ComponentScan
public class CDPlayConfig {
}

4阎姥、編寫(xiě)一個(gè)簡(jiǎn)單的JUnit例子

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayConfig.class)
public class CDPlayConfigTest {

    @Autowired
    private CompactDisc cd;

    @Test
    public void cdShouldNotBeNull(){
        assertNotNull(cd);
    }
} 

在上面的JUnit的例子中绎狭,類(lèi)的頭部包含了@RunWith注解和@ContextConfiguration注解,其中RunWith中的SpringJUnit4ClassRunner.class將會(huì)為我們創(chuàng)建Spring應(yīng)用的上下文眉抬,ContextConfiguration中的classes = CDPlayConfig.class則表明我們將在CDPlayConfig中加載配置
運(yùn)行吴藻,會(huì)發(fā)現(xiàn)JUnit的測(cè)試是通過(guò)的

為被裝配的組件命名

Spring應(yīng)用的上下文中的所有的bean都會(huì)有一個(gè)ID來(lái)標(biāo)識(shí)自己瞒爬,假如我們不強(qiáng)制指定,那么Spring會(huì)根據(jù)類(lèi)名為其指定一個(gè)ID调缨,一般會(huì)把類(lèi)的第一個(gè)字母小寫(xiě)來(lái)作為ID疮鲫,比如上面的SgtPeppers,那么這個(gè)bean的ID就是sgtPeppers,我們也可以自己指定ID弦叶,有兩種方式俊犯,分別如下
第一種是在Component里面直接寫(xiě)上ID

@Component("lonelyHeartClub")
public class SgtPeppers implements CompactDisc {
    ...
}

第二種是使用DI的參數(shù)@Named注解,如下

@Named("lonelyHeartClub")
public class SgtPeppers implements CompactDisc {
    ...
}

不過(guò)推薦使用第一種

對(duì)于@ComponentScan的注解伤哺,假如我們不指定掃描的包燕侠,那么就會(huì)掃描配置類(lèi)當(dāng)前所在的包,我們也可以指定我們需要進(jìn)行掃描的包立莉,如下

@ComponentScan(basePackages = "com.fan.soundsystem")
public class CDPlayConfig {
}

不過(guò)也可以使用類(lèi)所在包作為掃描的包绢彤,如下

@Configuration
@ComponentScan(basePackageClasses = CDPlayConfig.class)
public class CDPlayConfig {
}

@Autowired是自動(dòng)裝配注解,表明會(huì)在上下文中搜索bean并裝配到參數(shù)之中蜓耻,假如沒(méi)有匹配的bean茫舶,那么就會(huì)拋出異常,為了避免異常的發(fā)生刹淌,我們可以設(shè)置@Autowired的required屬性為false饶氏。我們同樣可以使用@Inject來(lái)替代@Autowired,如下

@Inject
public void setCompactDisc(CompactDisc cd){
    this.cd = cd;
}
通過(guò)JavaConfig進(jìn)行bean的裝配

1有勾、我們針對(duì)CompactDisc創(chuàng)建一個(gè)新的實(shí)現(xiàn)

@Component
public class Revolver implements CompactDisc {
    private String title = "Revolver";
    private String artist = "The Beatles";

    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }
}

2疹启、然后我們把CDPlayConfig 中的@ComponentScan注解移除,并添加我們自己寫(xiě)的注入,需要注意的是蔼卡,假如我們有兩個(gè)創(chuàng)建CompactDisc 的方法被增加了注解@bean喊崖,那么我們將得不到一個(gè)正確的結(jié)果,如下面注釋的部分不能出現(xiàn)

@Configuration
public class CDPlayerConfig1 {
//    @Bean
//    public CompactDisc sgtCompactDisc(){
//        return new SgtPeppers();
//    }
    @Bean
    public CompactDisc randomBeatlesCD(){
        int choice = (int) Math.floor(Math.random() * 4);
        if(choice == 0){
            return new SgtPeppers();
        }else {
            return new Revolver();
        }
    }

    @Bean
    public CDPlayer cdPlayer(){
        return new CDPlayer(randomBeatlesCD());
    }
}

3、對(duì)JUnit的實(shí)例做一下簡(jiǎn)單的修改

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig1.class)
public class CDPlayConfigTest {
//    @Rule
//    public final StandardOutputStreamLog log = new

    @Autowired
    private CDPlayer cd;

    @Test
    public void cdShouldNotBeNull(){
        assertNotNull(cd.getCompactDisc());
    }

這樣同樣能夠取得相同的效果

通過(guò)XML進(jìn)行bean的裝配

基于XML裝配bean的方法配置風(fēng)格有兩種,分別為

<constructor-arg>元素
使用Spring3.0所引入的c空間

使用<constructor-arg>的配置文件如下所示

<?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">

       <bean id="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
       <bean id="cdPlayer" class="com.fan.soundsystem.CDPlayer">
              <constructor-arg ref="compactDisc"/>
       </bean>
</beans>

我們可以通過(guò)這種方式來(lái)獲取bean

使用c命名空間的方式配置如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       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="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
       <bean id="cdPlayer" class="com.fan.soundsystem.CDPlayer" c:cd-ref="compactDisc"/>
</beans>

我們?yōu)樯厦娴呐渲镁帉?xiě)一個(gè)測(cè)試方法荤懂,如下

public class Main {
    public static void main(String[] args){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
        CDPlayer cd = context.getBean(CDPlayer.class);
        cd.getCompactDisc().play();
        context.close();
    }
}

c命名空間相比之下更加的靈活
我們有時(shí)候需要將字面量注入到bean之中茁裙,我們?cè)谶@種情況下該怎么做呢?
如下势誊,我們先創(chuàng)建一個(gè)類(lèi)呜达,并不設(shè)置任何注解

public class BlankDisc implements CompactDisc {
    private String title;
    private String artist;
    private List<String> tracks;

    public BlankDisc(String title,String artist,List<String> tracks){
        this.title = title;
        this.artist = artist;
        this.tracks = tracks;
    }


    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
        for(String track : tracks)
            System.out.println("-Track:" + track);
    }
}

然后利用配置給這個(gè)bean進(jìn)行配置

<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc">
              <constructor-arg value="Sgt. Pepper's Lonely Hearts Clubs Band"/>
              <constructor-arg value="The Beatles"/>
              <constructor-arg>
                     <list>
                            <value>Sgt. Peper's Lonely Hearts Club Band</value>
                            <value>Fixing a Hole</value>
                     </list>
              </constructor-arg>
       </bean>

和引用注入一樣谣蠢,我們同樣可以使用c命名空間進(jìn)行注入粟耻,如下

<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc"
               c:title="Sgt. Pepper's Hearts Club Band"
               c:artist="The Beatles"
               c:tracks-ref="trackList"/>

以上都是構(gòu)造器注入的方法,有時(shí)候我們需要對(duì)屬性進(jìn)行注入眉踱,那么我們可以使用下面這種方式挤忙,首先我們需要改造一下BlankDisc的寫(xiě)法

public class BlankDisc implements CompactDisc {
    private String title;
    private String artist;
    private List<String> tracks;

//    public BlankDisc(String title,String artist,List<String> tracks){
//        this.title = title;
//        this.artist = artist;
//        this.tracks = tracks;
//    }

    public void setTitle(String title){this.title = title;}
    public void setArtist(String artist){this.artist = artist;}
    public void setTracks(List<String> tracks){this.tracks = tracks;}


    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
        for(String track : tracks)
            System.out.println("-Track:" + track);
    }
}

注意其中的構(gòu)造器必須注釋掉,否則會(huì)出錯(cuò)谈喳,然后我們對(duì)配置文件進(jìn)行編寫(xiě)

<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc">
              <property name="title" value="Sgt. Pepper's Lonely Hearts Club Band"/>
              <property name="artist" value="The Beatles"/>
              <property name="tracks">
                     <list>
                            <value>Getting Better</value>
                            <value>Fixing a Hole</value>
                     </list>
              </property>
       </bean>

同樣册烈,我們還可以使用p空間進(jìn)行配置,看下面

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       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/util
                            http://www.springframework.org/schema/util/spring-util.xsd">

       <bean id="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
       
       <util:list id="trackList">
              <value>Getting Better</value>
              <value>Fixing a Hole</value>
       </util:list>
       <bean id="blankDisc" class="com.fan.soundsystem.BlankDisc"
             p:title="Sgt. Pepper's Lonely Hearts Club Band"
             p:artist="The Beatles"
             p:tracks-ref="trackList"/>
</beans>
混合配置

在通常的使用中婿禽,我們不僅可以使用上面3中方式的任何一種赏僧,而且我們還可以將各種方式進(jìn)行組合使用,常見(jiàn)的做法是在JavaConfig中引用XML和在XML中引用JavaConfig扭倾,那么我們應(yīng)該怎么做才能達(dá)到這一點(diǎn)呢

JavaConfig中引用XML

假如我們?cè)谝粋€(gè)測(cè)試單元中同事使用CDPlayer和BlankDisc淀零,那么我們可以對(duì)CDPlayerConfig1 增加對(duì)BlankDisc的配置,如下所示

@Configuration
@ImportResource("classpath:springConfig.xml")
public class CDPlayerConfig1 {
//    @Bean
//    public CompactDisc sgtCompactDisc(){
//        return new SgtPeppers();
//    }
    @Bean
    public CompactDisc randomBeatlesCD(){
        int choice = (int) Math.floor(Math.random() * 4);
        if(choice == 0){
            return new SgtPeppers();
        }else {
            return new Revolver();
        }
    }

    @Bean
    public CDPlayer cdPlayer(){
        return new CDPlayer(randomBeatlesCD());
    }
}

我們?cè)傩薷囊幌聹y(cè)試單元的代碼膛壹,如下

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig1.class)
public class CDPlayConfigTest {
//    @Rule
//    public final StandardOutputStreamLog log = new

    @Autowired
    private CDPlayer cd;

    @Autowired
    private BlankDisc bd;

    @Test
    public void cdShouldNotBeNull(){
        assertNotNull(cd.getCompactDisc());
        assertNotNull(bd);
    }
} 

運(yùn)行并查看運(yùn)行的結(jié)果驾中,如下所示

XML中引用JavaConfig

我們先創(chuàng)建一個(gè)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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
       <import resource="springConfig.xml"/>
       <bean class="com.fan.soundsystem.CDPlayerConfig1"/>
</beans>

再編寫(xiě)測(cè)試文件模聋,如下

public static void main(String[] args){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("TotalConfig.xml");
        AnnotationConfigApplicationContext context1 = new AnnotationConfigApplicationContext(CDPlayerConfig1.class);
        BlankDisc bd = context.getBean(BlankDisc.class);
        CDPlayer cdPlayer1 = context1.getBean(CDPlayer.class);
//        CDPlayer cdPlayer = context1.getBean(CDPlayer.class);
        cdPlayer1.play();
        bd.play();
        context.close();
    }

運(yùn)行并查看結(jié)果

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肩民,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子链方,更是在濱河造成了極大的恐慌持痰,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件祟蚀,死亡現(xiàn)場(chǎng)離奇詭異工窍,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)暂题,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)移剪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人薪者,你說(shuō)我怎么就攤上這事纵苛。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵攻人,是天一觀(guān)的道長(zhǎng)取试。 經(jīng)常有香客問(wèn)我,道長(zhǎng)怀吻,這世上最難降的妖魔是什么瞬浓? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蓬坡,結(jié)果婚禮上猿棉,老公的妹妹穿的比我還像新娘。我一直安慰自己屑咳,他們只是感情好萨赁,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著兆龙,像睡著了一般杖爽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上紫皇,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天慰安,我揣著相機(jī)與錄音,去河邊找鬼聪铺。 笑死化焕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的计寇。 我是一名探鬼主播锣杂,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼番宁!你這毒婦竟也來(lái)了元莫?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蝶押,失蹤者是張志新(化名)和其女友劉穎踱蠢,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體棋电,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡茎截,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赶盔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片企锌。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖于未,靈堂內(nèi)的尸體忽然破棺而出撕攒,到底是詐尸還是另有隱情陡鹃,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布抖坪,位于F島的核電站萍鲸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏擦俐。R本人自食惡果不足惜脊阴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蚯瞧。 院中可真熱鬧嘿期,春花似錦、人聲如沸状知。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)饥悴。三九已至,卻和暖如春盲再,著一層夾襖步出監(jiān)牢的瞬間西设,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工答朋, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贷揽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓梦碗,卻偏偏與公主長(zhǎng)得像禽绪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子洪规,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容