Spring核心 裝配Bean

Spring配置的可選方案

Spring容器負責建立應用程序中的bean並經過DI來協調這些對象之間的關係。當描述bean如何進行裝配時,Spring具備很是大的靈活性,它提供了三種主要的裝配機制:html

  • 在XML中進行顯式配置java

  • 在Java中進行顯式配置git

  • 隱式的bean發現機制和自動裝配github

儘量地使用自動配置的機制。顯式配置越少越好。當你必需要顯式配置bean的時候(好比,有些源碼不是由你來
維護的,而當你須要爲這些代碼配置bean的時候),推薦使用類型安全而且比XML更增強大的JavaConfig。最後,只有想要使用便利的XML命名空間,而且在JavaConfig中沒有一樣的實現時,才應該使用XMLspring

自動化裝配bean

Spring從兩個角度來實現自動化裝配:數組

  • 組件掃描(component scanning):Spring會自動發現應用上下文中所建立的bean安全

  • 自動裝配(autowiring):Spring自動知足bean之間的依賴ide

組件掃描和自動裝配組合在一塊兒就能發揮出強大的威力,它們可以將顯式配置下降到最少測試

建立可被發現的bean

CompactDisc接口在Java中定義了CD的概念

package soundsystem;

public interface CompactDisc
{
    void play();
}

CompactDisc的具體內容並不重要,重要的是你將其定義爲一個接口。做爲接口,它定義了CD播放器對一盤CD所能進行的操做。它將CD播放器的任意實現與CD自己的耦合下降到了最小的程度優化

帶有@Component註解的CompactDisc實現類SgtPeppers

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類上使用了@Component註解。這個簡單的註解代表SgtPeppers類會做爲組件類,並告知Spring要爲這個類建立bean。沒有必要顯式配置SgtPeppersbean,由於這個類使用了@Component註解,因此Spring會爲你把事情處理穩當

不過,組件掃描默認是不啓用的。咱們還須要顯式配置一下Spring,從而命令它去尋找帶有@Component註解的類,併爲其建立bean

@ComponentScan註解啓用了組件掃描

如下程序的配置類展示了完成這項任務的最簡潔配:

package soundsystem;
import org.springframework.context.annotation.componentScan;
import org.springframework.context.annotation.Con;
    
@Component
@ComponentScan
public class CDPlayerConfig{}

類CDPlayerConfig經過Java代碼定義了Spring的裝配規則。觀察可知,CDPlayerConfig類並無顯式地聲明任何bean,只不過它使用了@ComponentScan註解,這個註解可以在Spring中啓用組件掃描

若是沒有其餘配置的話,@ComponentScan默認會掃描與配置類相同的包。由於CDPlayerConfig類位於soundsystem包中,所以Spring將會掃描這個包以及這個包下的全部子包,查找帶有@Component註解的類。這樣的話,就能發現CompactDisc,而且會在Spring中自動爲其建立一個bean

經過XML啓用組件掃描

如更傾向於使用XML來啓用組件掃描的話,那麼可使用Spring context命名空間的<context:component-scan>元素。如下程序展現了啓用組件掃描的最簡潔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/comtext"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/beans/context
        http://www.springframework.org/schema/beans/context/spring-context.xsd">
        
    <context:component-scan base-package="soundsystem"/>
    
</beans>

測試組件掃描可以發現CompactDisc

package soundsystem;

import static org.junit.Assert.*;

import org.junit.Test;
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
{
    @Autowired
    private CompactDisc cd;
    
    @test_139772[test] 
    public void cdShouldNotBeNull()
    {
        assertNotNull(cd);
    }
}

CDPlayerTest使用了Spring的SpringJUnit4ClassRunner,以便在測試開始的時候自動建立Spring的應用上下文。註解@ContextConfiguration會告訴它須要在CDPlayerConfig中加載配置。由於CDPlayerConfig類中包含了@ComponentScan,所以最終的應用上下文中應該包含CompactDiscbean

在測試代碼中有一個CompactDisc類型的屬性,而且這個屬性帶有@Autowired註解,以便於將CompactDiscbean
注入到測試代碼之中。最後,會有一個簡單的測試方法斷言cd屬性不爲null。若是它不爲null的話,就意味着Spring可以發現CompactDisc類,自動在Spring上下文中將其建立爲bean並將其注入到測試代碼之中

爲組件掃描的bean命名

Spring應用上下文中全部的bean都會給定一個ID。前面的例子中,儘管沒有明確地爲SgtPeppersbean設置ID,但Spring會根據類名爲其指定一個ID。具體來說,這個bean所給定的ID爲sgtPeppers,也就是將類名的第一個字母變爲小寫

若想爲這個bean設置不一樣的ID,則需將指望的ID做爲值傳遞給@Component註解:

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

另一種爲bean命名的方式,使用Java依賴注入規範(Java Dependency Injection)中所提供的@Named註解來爲bean設置ID:

package soundsystem;
import javax.inject.Named;
@Named("lonelyHeartsClub")
public class SgtPeppers implements CompactDisc
{
    ...
}

設置組件掃描的基礎包

爲了指定不一樣的基礎包,所須要在@ComponentScan的value屬性中指明包的名稱:

@Configuration
@ComponentScan("soundsystem")
public class CDPlayerConfig{}

若需更加清晰地代表你所設置的是基礎包,經過basePackages屬性進行配置:

@Configuration
@ComponentScan(basePackages = "soundsystem")
public class CDPlayerConfig{}

若是須要能夠設置多個基礎包,只須要將basePackages屬性設置爲要掃描包的一個數組便可:

@Configuration
@ComponentScan(basePackages = {"soundsystem", 「videos」})
public class CDPlayerConfig{}

上面例子中,所設置的基礎包是以String類型表示的。這是可行的,但這種方法是類型不安全(not type-safe)的。如進行代碼重構,那麼所指定的基礎包可能會出現錯誤

除了將包設置爲簡單的String類型以外,@ComponentScan提供的另一種方法,將其指定爲包中所包含的類或接口:

@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class})
public class CDPlayerConfig{}

經過爲bean添加註解實現自動裝配

自動裝配就是讓Spring自動知足bean依賴的一種方法,在知足依賴的過程當中,會在Spring應用上下文中尋找匹配某個bean需求的其餘bean。爲了聲明要進行自動裝配,咱們能夠藉助Spring的@Autowired註解

下述程序CDPlayer類。它的構造器上添加了@Autowired註解,這代表當Spring建立CDPlayerbean的時候,會經過這個構造器來進行實例化而且會傳入一個可設置給CompactDisc類型的bean

經過自動裝配,將一個CompactDisc注入到CDPlayer之中:

package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class CDPlayer implement MediaPlayer
{
    private CompactDisc cd;
    
    @Autowired
    public CDPlayer(CompactDisc cd)
    {
        this.cd = cd;
    }
    
    public void play
    {
        cd.play();
    }
}

@Autowired註解不只可以用在構造器上,還能用在屬性的Setter方法上。好比說,若是CDPlayer有一個setCompactDisc()方法,那麼能夠採用以下的註解形式進行自動裝配:

@Autowired
public void setCompactDisc(CompactDisc cd)

@Autowired註解能夠用在類的任何方法上。假設CDPlayer類有一個insertDisc()方法,那麼@Autowired可以像在setCompactDisc()上那樣,發揮徹底相同的做用:

@Autowired
public void insertDisc(CompactDisc cd)
{
    this.cd = cd;
}

無論是構造器、Setter方法仍是其餘的方法,Spring都會嘗試知足方法參數上所聲明的依賴。假若有且只有一個bean匹配依賴需求的話,那麼這個bean將會被裝配進來

若是沒有匹配的bean,那麼在應用上下文建立的時候,Spring會拋出一個異常。爲了不異常的出現,你能夠將@Autowired的required屬性設置爲false:

@Autowired
public CDPlayer(CompactDisc cd)
{
    this.cd = cd;
}

將required屬性設置爲false時,Spring會嘗試執行自動裝配,若沒有匹配的bean,Spring將會讓這個bean處於未裝配的狀態。但把required屬性設置爲false時,須要謹慎對待。若是代碼中沒有進行null檢查,處於未裝配狀態的屬性可能出現NullPointerException

@Autowired是Spring特有的註解。若是不肯代碼中處處使用
Spring的特定註解來完成自動裝配任務,可考慮替換爲@Inject:

package soundsystem;
import javax.inject.Inject;
import javax.inject.Named;

@Named
public class CDPlayer
{
    ...
    @Inject
    public CDPlayer(CompactDisc cd)
    {
        this.cd = cd;
    }
    ...
}

@Inject註解來源於Java依賴注入規範,該規範同時還定義了@Named註解。在自動裝配中,Spring同時支持@Inject和
@Autowired。儘管@Inject和@Autowired之間有着一些細微的差異,可是在大多數場景下,是能夠互相替換的

驗證自動裝配

圖片描述

除了注入CompactDisc,還將CDPlayerbean注入到測試代碼的player成員變量之中(它是更爲通用的MediaPlayer類型)。在play()測試方法中,咱們能夠調用CDPlayer的play()方法,並斷言它的行爲與預期一致

在測試代碼中使用System.out.println()。所以,該樣例中使用了StandardOutputStreamLog,是來源於System Rules庫(http://stefanbirkner.github.i...)的一個JUnit規則,該規則可以基於控制檯的輸出編寫斷言。SgtPeppers.play()方法的輸出將被髮送到控制檯上

經過Java代碼裝配bean

如想將第三方庫中的組件裝配到你的應用中,在這種狀況下沒法經過在它的類上添加@Component和@Autowired註解的方法實現自動化裝配

JavaConfig與其餘的Java代碼存在區別,在概念上,它與應用程序中的業務邏輯和領域代碼不一樣的。儘管都使用相同的語言進行表述,但JavaConfig是配置代碼。這意味着它不該該包含任何業務邏輯,JavaConfig也不該該侵入到業務邏輯代碼之中。儘管不是必須的,但一般會將JavaConfig放到單獨的包中,使它與其餘的應用程序邏輯分離開來,這樣對於它的意圖就不會產生困惑了

建立配置類

建立JavaConfig類的關鍵在於爲其添加@Configuration註解,@Configuration註解代表這個類是一個配置類,該類應該包含在Spring應用上下文中如何建立bean的細節

package soundsystem;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CDPlayerConfig
{
    ...
}

到此爲止,都是依賴組件掃描來發現Spring應該建立的bean。儘管能夠同時使用組件掃描和顯式配置,但在本節更加關注於顯式配置,所以將CDPlayerConfig的@ComponentScan註解移除掉了。移除了@ComponentScan註解,此時的CDPlayerConfig類就沒有任何做用了。如如今運行CDPlayerTest,測試失敗,並出現BeanCreation-Exception異常。測試指望被注入CDPlayer和CompactDisc,但這些bean根本就沒有建立,由於組件掃描不會發現它們。下一節,將展示如何使用JavaConfig裝配CDPlayer和CompactDisc

聲明簡單的bean

要在JavaConfig中聲明bean,需編寫一個建立所需類型實例的方法,而後給這個方法添加@Bean註解。以下代碼聲明瞭CompactDisc bean:

@Bean
public CompactDisc sgtPeppers()
{
    return new SgtPeppers();
}

@Bean註解會告訴Spring這個方法將會返回一個對象,該對象要註冊爲Spring應用上下文中的bean。方法體中包含了最終產生bean實例的邏輯

默認狀況下,bean的ID與帶有@Bean註解的方法名是同樣的。在本例中,bean的名字將會是sgtPeppers。若是你想爲其設置成一個不一樣的名字的話,那麼能夠重命名該方法,也能夠經過name屬性指定一個不一樣的名字:

@Bean(name= "lonelyHeartsClubBand")
public CompactDisc sgtPeppers()
{
    return new SgtPeppers();
}

藉助JavaConfig實現注入

前面所聲明的CompactDisc bean很是簡單,自身沒有其餘依賴。如今,須要聲明依賴於CompactDisc的CDPlayer bean。在JavaConfig中裝配bean的最簡單方式就是引用建立bean的方法。以下就是一種聲明CDPlayer的可行方案:

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

這個方法會建立一個bean實例並將其註冊到Spring應用上下文中。所建立的bean ID爲cdPlayer,與方法的名字相同。cdPlayer()的方法體與sgtPeppers()稍微有些區別。在這裏並無使用默認的構造器構建實例,而是調用了須要傳入CompactDisc對象的構造器來建立CDPlayer實例。看起來,CompactDisc是經過調用sgtPeppers()獲得的,但狀況並不是徹底如此。由於sgtPeppers()方法上添加了@Bean註解,Spring將會攔截全部對它的調用,並確保直接返回該方法所建立的bean,而不是每次都對其進行實際的調用

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

默認狀況下,Spring中的bean都是單例的,並不必爲第二個CDPlayer bean建立徹底相同的SgtPeppers實例。因此,Spring會攔截對sgtPeppers()的調用並確保返回的是Spring所建立的bean,也就是Spring自己在調用sgtPeppers()時所建立的CompactDiscbean。所以,兩個CDPlayer bean會獲得相同的SgtPeppers實例

@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc)
{
    return new CDPlayer(sgtPeppers());
}

在這裏,cdPlayer()方法請求一個CompactDisc做爲參數。當Spring調用cdPlayer()建立CDPlayerbean的時候,它會自動裝配一個CompactDisc到配置方法之中。而後,方法體就能夠按照合適的方式來使用它。藉助這種技術,cdPlayer()方法也可以將CompactDisc注入到CDPlayer的構造器中,並且不用明確引用CompactDisc的@Bean方法

經過這種方式引用其餘的bean一般是最佳的選擇,由於它不會要求將CompactDisc聲明到同一個配置類之中。在這裏甚至沒有要求CompactDisc必需要在JavaConfig中聲明,實際上它能夠經過組件掃描功能自動發現或者經過XML來進行配置

能夠將配置分散到多個配置類、XML文件以及自動掃描和裝配bean之中,只要功能完整健全便可。無論CompactDisc是採用什麼方式建立出來的,Spring都會將其傳入到配置方法中,並用來建立CDPlayer bean

經過XML裝配bean

建立XML配置規範

在使用XML爲Spring裝配bean以前,你須要建立一個新的配置規範。在使用JavaConfig的時候,這意味着要建立一個帶有@Configuration註解的類,而在XML配置中,這意味着要建立一個XML文件,而且要以<beans>元素爲根

<?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/beans/context">
        
    <!-- configuration details go here -->
    
</beans>

如上基本的XML配置已比同等功能的JavaConfig類複雜。在JavaConfig中只須要@Configuration,但在XML中,須要在配置文件的頂部聲明多個XML模式(XSD)文件,這些文件定義了配置Spring的XML元素

藉助Spring Tool Suite建立XML配置文件建立和管理Spring XML配置文件的一種簡便方式是使用Spring Tool Suite(https://spring.io/tools/sts)。在Spring Tool Suite的菜單中,選擇File>New>Spring Bean Configuration File,可以建立Spring XML配置文件,而且能夠選擇可用的配置命名空間

用來裝配bean的最基本的XML元素包含在spring-beans模式之中,在上面這個XML文件中,它被定義爲根命名空間。<beans>是該模式中的一個元素,它是全部Spring配置文件的根元素

聲明一個簡單的<bean>

要在基於XML的Spring配置中聲明一個bean,咱們要使用springbeans模式中的另一個元素:<bean>。<bean>元素相似於JavaConfig中的@Bean註解。能夠以下的方式聲明CompactDiscbean:

<bean class="soundsystem.SgtPeppers" />

這裏聲明瞭一個簡單的bean,建立這個bean的類經過class屬性來指定的,而且要使用全限定的類名

因沒明確給定ID,因此這個bean將會根據全限定類名來進行命名。在本例中,bean的ID將會是「soundsystem.SgtPeppers#0」。其中,「#0」是一個計數的形式,用來區分相同類型的其餘bean。若是你聲明瞭另一個SgtPeppers,而且沒有明確進行標識,那麼它自動獲得的ID將會是「soundsystem.SgtPeppers#1」

一般來說,更好的辦法是藉助id屬性,爲每一個bean設置一個你本身選擇的名字:

<bean id = "compactDisc" class="soundsystem.SgtPeppers" />

減小繁瑣爲了減小XML中繁瑣的配置,只對那些須要按名字引用的bean(好比,你須要將對它的引用注入到另一個bean中)進行明確地命名

藉助IDE檢查XML的合法性使用可以感知Spring功能的IDE,如Spring Tool Suite,可以在很大程度上幫助你確保Spring XML配置的合法性

藉助構造器注入初始化bean

在Spring XML配置中,只有一種聲明bean的方式:使用<bean>元素並指定class屬性。Spring會從這裏獲取必要的信息來建立bean。可是,在XML中聲明DI時,會有多種可選的配置方案和風格。具體到構造器注入,有兩種基本的配置方案可供選擇:

  • <constructor-arg>元素

  • 使用Spring 3.0所引入的c-命名空間

構造器注入bean引用

1.<constructor-arg>元素方案:
現已聲明SgtPeppers bean,而且SgtPeppers類實現了CompactDisc接口,因此實際上已經一個能夠注入到CDPlayerbean中的bean。所需作的是在XML中聲明CDPlayer並經過ID引用SgtPeppers:

<bean id="cdplayer" class="soundsystem.CDPlayer">
    <constructor-arg ref="compactDisc" />
</bean>

當Spring遇到這個<bean>元素時,會建立一個CDPlayer實例。<constructor-arg>元素會告知Spring要將一個ID
爲compactDisc的bean引用傳遞到CDPlayer的構造器中

2.c-命名空間方案:
c-命名空間是在XML中更爲簡潔地描述構造器參數的方式。要使用它的話,必需要在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:c="http://www.springframework.org/schema/c"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bar" class="x.y.Bar"/>
    <bean id="baz" class="x.y.Baz"/>

    <!-- 標準XML格式 -->
    <bean id="foo" class="x.y.Foo">
        <constructor-arg name="bar" ref="bar"/>
        <constructor-arg name="baz" ref="baz"/>
        <constructor-arg name="email" value="foo@bar.com"/>
    </bean>

    <!-- c命名空間格式 -->
    <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/>

    <!-- 還可使用c命名空間的參數索引格式 -->
    <bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz" c:_2="foo@bar.com"/>

</beans>

在c-命名空間和模式聲明以後,就可使用它來聲明構造器參數了,以下所示:

<bean id="cdplayer" class="soundsystem.CDPlayer"
    c:cd-ref="compactDisc" />

屬性名以「c:」開頭,也就是命名空間的前綴。接下來就是要裝配的構造器參數名,在此以後是「-ref」,這是一個命名的約定,它會告訴Spring,正在裝配的是一個bean的引用,這個bean的名字是compactDisc,而不是字面量「compactDisc」
圖片描述

引用參數的名稱有些怪異,由於須要編譯代碼時,將調試標誌(debug symbol)保存在類代碼中。若是優化構建過程,將調試標誌移除掉,那麼這種方式可能就沒法正常執行。根本不用去標示參數的方案:

<bean id="cdplayer" class="soundsystem.CDPlayer"
    c:_-ref="compactDisc" />

將字面量(literal value)注入到構造器中

迄今爲止,所作的DI一般指的都是類型的裝配——也就是將對象的引用裝配到依賴於它們的其餘對象之中——而有時須要的只是用一個字面量值來配置對象

1.<constructor-arg>元素方案:

package soundsystem;
public class BlankDisc implements CompactDisc
{
    private String title;
    private String artist;
    
    public BlankDisc(String title, String artist)
    {
        this.title = title;
        this.artist = artist;
    }
    
    public void play()
    {
        System.out.println("Playing" + title + "by" + artist);
    }
}
<bean id="compactDisc" class="soundsystem.BlankDisc">
    <constructor-arg value = "Sgt. Pepper's Lonely Hearts Club Band" />
    <constructor-arg value = "The Beatles" />
</bean>

上述程序使用<constructor-arg>元素進行構造器參數的注入。沒有使用「ref」屬性來引用其餘的bean,而使用了
value屬性,經過該屬性代表給定的值要以字面量的形式注入到構造器之中

2.c-命名空間方案:

引用構造器參數名:

<bean id="compactDisc" class="soundsystem.BlankDisc"
    c:_title="Sgt. Pepper's Lonely Hearts Club Band" 
    c:_artist="The Beatles" />

經過參數索引裝配相同的字面量值:

<bean id="compactDisc" class="soundsystem.BlankDisc"
    c:_0="Sgt. Pepper's Lonely Hearts Club Band"
    c:_1="The Beatles" />

裝配集合

含有磁道列表概念的BLankDisc

package soundsystem.collections;

import java.ytil.List;
import soundsystem.CompactDisc;

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 play()
    {
        System.out.println("Playing" + title + "by" + artist);
        for(String track : tracks)
        {
            System.out.println("-Track: " + track);
        }
    }
}

這個變動會對Spring如何配置bean產生影響,在聲明bean時,必需要提供一個磁道列表。較好的解決方法是提供一個磁道名稱的列表。首先,可使用<list>元素將其聲明爲一個列表:

<bean id="compactDisc" class="soundsystem.BlankDisc">
    <constructor-arg value = "Sgt. Pepper's Lonely Hearts Club Band" />
    <constructor-arg value = "The Beatles" />
    <constructor-arg>
        <list>
            <value>Sgt. Pepper's Lonely Hearts Club Band</value>
            <value>With a Little Help from My Friend</value>
            <value>Lucy in the Sky with Diamonds</value>
            <value>Getting Better</value>
            <value>Fixing a Hole</value>
            <!-- ...other tracks omiitted for brevity... ->
        </list>
    </constructor-arg>
</bean>

其中,<list>元素是<constructor-arg>的子元素,這代表一個包含值的列表將會傳遞到構造器中。其中,<value>元素用來指定列表中的每一個元素

也可以使用<ref>元素替代<value>,實現bean引用列表的裝配。假設有一個Discography類,構造器以下所示:

public Discography(String artist, List<CompactDisc> cds)
{
    ...
}

採起以下的方式配置Discography bean:

<bean id="beatlesDiscography" class="soundsystem.Discography">
    <constructor-arg value = "The Beatles" />
    <constructor-arg>
        <list>
            <ref bean="SgtPeppers" />
            <ref bean="whiteAlbum" />
            <ref bean="hardDaysNight" />
            <ref bean="revolver" />
            ...
        </list>
    </constructor-arg>
</bean>

在裝配集合方面,<constructor-arg>比c-命名空間的屬性更有優點。目前,使用c-命名空間的屬性沒法實現裝配集合的功能。使用<constructor-arg>和c-命名空間實現構造器注入時,它們之間還有一些細微的差異

設置屬性

使用Spring XML實現屬性注入

設屬性注入的CDPlayer以下所示:

package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import soundsystem.CompactDisc;
import soundsystem.MediaPlayer;

public class CDPlayer implement MediaPlayer
{
    private CompactDisc compactDisc;
    
    @Autowired
    public CDPlayer(CompactDisc compactDisc)
    {
        this.compactDisc = compactDisc;
    }
    
    public void play
    {
        compactDisc.play();
    }
}

做爲一個通用的規則,強依賴使用構造器注入,而對可選性的依賴使用屬性注入

p-命名空間:

<?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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 標準XML格式 -->
    <bean name="john-classic" class="com.example.Person">
        <property name="name" value="John Doe"/>
        <property name="spouse" ref="jane"/>
    </bean>

    <!-- p命名空間格式 -->
    <bean name="john-modern"
        class="com.example.Person"
        p:name="John Doe"
        p:spouse-ref="jane"/>

</beans>

使用p-命名空間裝配compactDisc屬性:

<bean id = "cdplayer"
      class = "soundsystem.CDPlayer"
      p:compactDisc-ref = "compactDisc" />

圖片描述

屬性的名字使用了「p:」前綴,代表咱們所設置的是一個屬性。接下來就是要注入的屬性名。最後,屬性的名稱以「-ref」結尾,這會提示Spring要進行裝配的是引用,而不是字面量

將字面量注入到屬性中

如下BlankDisc徹底經過屬性注入進行配置,而不是構造器注入。新的BlankDisc類以下所示:

package soundsystem.collections;

import java.ytil.List;
import soundsystem.CompactDisc;

public class BlankDisc implements CompactDisc
{
    private String title;
    private String artist;
    private List<String> tracks;
    
    public setTitle(String title)
    {
        this.title = title;
    }
    
    public setArtistString artist)
    {
        this.artist = artist;
    }
            
    public setTracks(List<String> tracks)
    {
        this.tracks = tracks;
    }
    
    public void play()
    {
        System.out.println("Playing" + title + "by" + artist);
        for(String track : tracks)
        {
            System.out.println("-Track: " + track);
        }
    }
}

藉助<property>元素的value屬性裝配這些屬性,內嵌<list>元素設置tracks屬性:

<bean id="compactDisc" class="soundsystem.BlankDisc">
    <property name = "title" value = "Sgt. Pepper's Lonely Hearts Club Band" />
    <property name = "artist" value = "The Beatles" />
    <property name = "tracks">
        <list>
            <value>Sgt. Pepper's Lonely Hearts Club Band</value>
            <value>With a Little Help from My Friend</value>
            <value>Lucy in the Sky with Diamonds</value>
            <value>Getting Better</value>
            <value>Fixing a Hole</value>
            <!-- ...other tracks omiitted for brevity... ->
        </list>
    </property>
</bean>

使用p-命名空間:

<bean id = "compactDisc" 
    class="soundsystem.BlankDisc"
    p:title = "Sgt. Pepper's Lonely Hearts Club Band"
    p:artist = "The Beatles">
    <property name = "tracks">
        <list>
            <value>Sgt. Pepper's Lonely Hearts Club Band</value>
            <value>With a Little Help from My Friend</value>
            <value>Lucy in the Sky with Diamonds</value>
            <value>Getting Better</value>
            <value>Fixing a Hole</value>
            <!-- ...other tracks omiitted for brevity... ->
        </list>
    </property>
</bean>

與c-命名空間同樣,裝配bean引用與裝配字面量的惟一區別在因而否帶有「-ref」後綴。若是沒有「-ref」後綴的話,所裝配的就是字面量

不能使用p-命名空間來裝配集合,沒有便利的方式使用p-命名空間來指定一個值(或bean引用)的列表。但可使用Spring util-命名空間中的一些功能來簡化BlankDiscbean

首先,須要在XML中聲明util-命名空間及其模式:

<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://http://www.springframework.org/schema/util"
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">
    ...
</beans>

util-命名空間所提供的功能之一就是<util:list>元素,它會建立一個列表的bean。<util:list>可將磁道列表轉移到BlankDisc bean以外,並將其聲明到單獨的bean之中,以下所示:

<util:list id = "trackList">
    <value>Sgt. Pepper's Lonely Hearts Club Band</value>
    <value>With a Little Help from My Friend</value>
    <value>Lucy in the Sky with Diamonds</value>
    <value>Getting Better</value>
    <value>Fixing a Hole</value>
    <!-- ...other tracks omiitted for brevity... ->
</util:list>

將磁道列表bean注入到BLANkDisc bean的tracks屬性中:

<bean id = "compactDisc" class = "soundsystem.BlankDisc"
    p:title = "Sgt. Pepper's Lonely Hearts Club Band"
    p:artist = "The Beatles"
    p:tracks-ref = "trackList" />
元素 描述
<util:constant> 引用某個類型的public static域,並將其暴露爲bean
<util:list> 建立一個java.util.List類型的bean,其中包含值或引用
<util:map> 建立一個java.util.Map類型的bean,其中包含值或引用
<util:properties> 建立一個java.util.properties類型的bean
<util:property-path> 引用一個bean的屬性(或內嵌屬性),並將其暴露爲bean
<util:set> 建立一個java.util.Set類型的bean,其中包含值或引用

導入和混合配置

在JavaConfig中引用XML配置

如今假設CDPlayerConfig已經有些笨重,所以將其進行拆分。雖然目前只定義了兩個bean,遠遠稱不上覆雜Spring配置。不過,在此假設兩個bean已經算多了。一種方案是將BlankDisc從CDPlayerConfig拆分出來,定義到它本身的CDConfig類中,以下所示:

package soundsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CDConfig
{
    @Bean
    public CompactDisc compactDisc()
    {
        return new SgtPeppers();
    }
}

上述程序的compactDisc()方法已經從CDPlayerConfig中移除掉了,現須要將這兩個類組合在一塊兒。一種方法就是
在CDPlayerConfig中使用@Import註解導入CDConfig:

package soundsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;    

@Configuration
@Import(CDConfig.class)
public class CDPlayerConfig
{
    @Bean
    public CDPlayer cdPlayer(CompactDisc compactDisc)
    {
        return new CDPlayer(compactDisc);
    }
}

更好的辦法,不在CDPlayerConfig中使用@Import,而是建立一個更高級別的SoundSystemConfig,在
這個類中使用@Import將兩個配置類組合在一塊兒:

package soundsystem;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;    

@Configuration
@Import(CDConfig.class)
public class CDPlayerConfig
{
    @Bean
    public CDPlayer cdPlayer(CompactDisc compactDisc)
    {
        return new CDPlayer(compactDisc);
    }
}

更好的辦法,不在CDPlayerConfig中使用@Import,而是建立一個更高級別的SoundSystemConfig,在這個類中使用@Import將兩個配置類組合在一塊兒:

package soundsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({CDPlayerConfig.class, CDConfig.class})
public class SoundSystemConfig
{
}

現已將CDPlayer的配置與BlankDisc的配置分開,假設(基於某些緣由)但願經過XML來配置BlankDisc,以下所示:

<bean id="compactDisc" class="soundsystem.BlankDisc">
    <c:_0 = "Sgt. Pepper's Lonely Hearts Club Band" />
    <c:_1 = "The Beatles" />
    <constructor-arg>
        <list>
            <value>Sgt. Pepper's Lonely Hearts Club Band</value>
            <value>With a Little Help from My Friend</value>
            <value>Lucy in the Sky with Diamonds</value>
            <value>Getting Better</value>
            <value>Fixing a Hole</value>
            <!-- ...other tracks omiitted for brevity... ->
        </list>
    </constructor-arg>
</bean>

使用@ImportResource註解同時加載XML配置和其餘基於Java的配置,假設BlankDisc定義在名爲cdconfig.
xml的文件中,該文件位於根類路徑下,那麼能夠修改SoundSystemConfig,讓它使用@ImportResource註解,以下所示:

package soundsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig
{
}

在XML配置中引用JavaConfig

在JavaConfig配置中,使用@Import和@ImportResource來拆分JavaConfig類。在XML中,使用import元素來拆分XML配置

設但願將BlankDisc bean拆分到本身的配置文件中,該文件名爲cd-config.xml,這與以前使用@ImportResource是同樣的。課在XML配置文件中使用<import>元素來引用該文件:

<?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:c="http://www.springframework.org/schema/c"    
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <import resoune = "cd-config.xml"/>
    <bean id = "cdPlayer" class = "soundsystem.CDPlayer" c:cd-ref = "compactDisc"/>
</beans>
相關文章
相關標籤/搜索