1

<div style="font-size:34px">Spring4參考手冊中文版</div>

<h1>作者簡介</h1>
翻譯 鐵柱 wwwshiym@gmail.com
顧問 張丙天

鐵柱 曾任中科軟科技股份有限公司應(yīng)用系統(tǒng)事業(yè)群部技術(shù)副總監(jiān)、首席架構(gòu)師,2008年加入中科軟。擅長SOA、企業(yè)信息化架構(gòu),精通Java、Spring,在多線程、io、虛擬機(jī)調(diào)優(yōu)、網(wǎng)絡(luò)通信及支撐大型網(wǎng)站的領(lǐng)域有較多經(jīng)驗(yàn),對技術(shù)有濃厚的興趣?,F(xiàn)致力于無線、數(shù)據(jù)、業(yè)務(wù)平臺、組件化方面取得突破。

張丙天

<h1>前言</h1>
我是前言。

<h1 id="spring-core">Part III. 核心技術(shù)</h1>
本部分參考手冊完全覆蓋了Srping 框架的全部技術(shù)

首先是Spring IoC控制反轉(zhuǎn)。深入徹底的IoC講解之后,緊隨其后的是全面解說Spring AOP。Spring有自己的AOP框架,該框架概念簡單易于理解,能解決Java企業(yè)應(yīng)用中80%的需求

Spring也集成了AspectJ,AspectJ是現(xiàn)今java領(lǐng)域功能最豐富、最成熟的AOP實(shí)現(xiàn)。

最后面的部分是tdd測試驅(qū)動開發(fā),也是Spring 開發(fā)團(tuán)隊(duì)最為推崇的開發(fā)方法,主要內(nèi)容有單元測試和spirng對集成測試的支持。Spring 團(tuán)隊(duì)發(fā)現(xiàn),正確的使用Ioc,會使單元測試和集成測試更加簡單(因?yàn)轭愔惺褂肧etter和構(gòu)造函數(shù),將使它們更容易的配合,而無需使用set up組裝)。同時(shí),為測試弄了專門的單獨(dú)章節(jié),希望你能領(lǐng)悟這一點(diǎn)

<h2 id="beans">IoC容器</h2>
<h3 id="beans-introduction">springIOC容器和beans簡介</h3>

本章講解spring的控制反轉(zhuǎn)(IoC)的spring 框架實(shí)現(xiàn) [1] 原理. IoC 又名 依賴注入 (DI). 它是一個(gè)由對象定義依賴的處理手法,也就是如何與其他對象協(xié)同工作, 可以通過以下途徑定義依賴:構(gòu)造參數(shù)注入、工廠方法的參數(shù)注入、屬性注入(是指對象實(shí)例化后或者從工廠方法返回一個(gè)實(shí)例后設(shè)置其屬性)。容器創(chuàng)建bean時(shí)候, 注入 依賴。 這個(gè)控制倒轉(zhuǎn)了, 因此得名控制反轉(zhuǎn) (IoC)。反轉(zhuǎn)了哪些控制,不再是由bean自己控制依賴類的實(shí)例化和定位, 而是使用了類似于 服務(wù)定位 模式的機(jī)制來控制。

org.springframework.beansorg.springframework.context 這兩個(gè)包是spring IOC容器的基礎(chǔ)包. BeanFactory 接口 提供了各種配置,用于管理任何對象. ApplicationContextBeanFactory的子接口. 它提供以下功能,使集成Spring’s AOP功能 更容易; 消息資源處理(用于國際化);事件發(fā)布;應(yīng)用層指定上下文環(huán)境,像用于web應(yīng)用的WebApplicationContext.

簡而言之, BeanFactory 提供了配置框架和基礎(chǔ)功能, ApplicationContext 增加了更多的企業(yè)應(yīng)用用能. ApplicationContextBeanFactory的超集, 是本章的spring IOC示例中的指定容器. 用BeanFactory 替代 ApplicationContext, 更多的信息請參看 Section 4.17, “The BeanFactory”.

應(yīng)用中的對象并且是由spring 容器 管理的,被稱為beans.就是對象,由spring容器管理的諸如實(shí)例化、組裝等等操作. bean可以由應(yīng)用中的多個(gè)對象組成。Bean通過容器和配置元數(shù)據(jù) ,使用反射技術(shù),去組裝依賴對象。

<h3 id="beans-basics">容器概述</h3>
接口org.springframework.context.ApplicationContext代表了srping IoC 容器,負(fù)責(zé)實(shí)例化、配置和組裝前面提到的beans。容器依據(jù)配置配置元數(shù)據(jù)去實(shí)例化、配置、組裝。配置元數(shù)據(jù)可以用XML、Java 注解、或者Java編碼表示。在配置元數(shù)據(jù)中,可以定義組成應(yīng)用的對象,以及對象之間的依賴關(guān)系。

Spring 提供了一些開箱即用的ApplicationContext接口的實(shí)現(xiàn)。在單獨(dú)的應(yīng)用中,通常使用ClassPathXmlApplicationContext或者FileSystemXmlApplicationContext。當(dāng)使用XML定義配置元數(shù)據(jù)時(shí),可通過一小段xml配置使容器支持其他格式的配置元數(shù)據(jù),比如Java 注解、Java Code。

大多數(shù)的應(yīng)用場景中,不需要硬編碼來實(shí)例化一個(gè)Spring IoC 的容器。舉個(gè)栗子,web應(yīng)用中,在web.xml中大概8行左右的配置就可以實(shí)例化一個(gè)Spring Ioc容器(see Section 4.16.4, “Convenient ApplicationContext instantiation for web applications”)。若再有STS(Spring eclipse 套件),簡單的鉤鉤點(diǎn)點(diǎn)即可完成此配置。

下面的示意圖是spring工作原理。ApplicationContext將應(yīng)用中的類與配置元數(shù)據(jù)相結(jié)合,實(shí)例化后,即可得到一個(gè)可配置、可執(zhí)行的系統(tǒng)或應(yīng)用。
The Spring IoC container

spring 工作原理示意圖

<h4 id="beans-factory-metadata">配置元數(shù)據(jù)</h4>
如上圖所示,Spring IoC容器使用某種格式的配置元數(shù)據(jù);配置元數(shù)據(jù),就是告訴Ioc容器如何將對象實(shí)例化、配置、組裝。

配置元數(shù)據(jù)是默認(rèn)使用簡單直觀的xml格式,也是本章樣例中使用最多的,這些樣例程序用以說明spring Ioc 容器的核心概念和功能

注意

基于XML的元數(shù)據(jù)并不是唯一的格式。Spring IoC容器已經(jīng)和提及到的元數(shù)據(jù)格式完全解耦了。目前,很多碼農(nóng)都選擇Java-based configuration

欲了解其他元數(shù)據(jù)格式的使用,請參看:

  • Annotation-based configuration: Spring 2.5 引進(jìn)的支持java 注解配置元數(shù)據(jù)
  • Java-based configuration: Spring3.0時(shí),將Spring JavaConfig project的很多功能集成到核心Spring框架中。Thus you can define beans external to your application classes by using Java rather than XML files.你可以使用java配置類定義bean,無需xml,該配置類與應(yīng)用類無關(guān)。想要嘗鮮的話,請參看@Configuration,@Bean,@Import,@DependsOn注解

Spring配置由Spring bean的定義組成,這些bean必須被容器管理,至少1個(gè),通常會有多個(gè)。基于XML的配置元數(shù)據(jù),大概這么配置,根節(jié)點(diǎn)<beans>中配置子節(jié)點(diǎn)<bean>。Java configuration使用是這樣的,一個(gè)帶有@Configuration類注解的類中,方法上使用@Bean方法注解。

bean的定義要與應(yīng)用中實(shí)際的類相一致??梢远xservice 層的對象、Dao對象、類似Struts的表現(xiàn)成的對象、像Hibernate SessionFactories這樣的基礎(chǔ)對象,JMS隊(duì)列等等。通常不會去定義細(xì)粒度域?qū)ο螅驗(yàn)樗鼈冇蒁AO或者Service負(fù)責(zé)創(chuàng)建、加載。然而,通過集成AspectJ,可以配置非Srping容器創(chuàng)建的對象。參看Using AspectJ to dependency-inject domain objects with Spring

下面的樣例展示了基于XML配置元數(shù)據(jù)的基本格式:

<?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="..." class="...">
    <!-- bean的詳細(xì)配置 -->
    </bean>
    
    <bean id="..." class="...">
    <!-- bean的詳細(xì)配置 -->
    </bean>
    
    <!-- 其他bean -->

</beans>

id屬性是個(gè)字串,是bean的唯一標(biāo)示符。class屬性定義了bean的類型,要使用類的全限定類名(含有包路徑)。id屬性的值,可以作為合作bean的引用標(biāo)示符。上面未展示如何引用其他對象;詳情參看Dependencies

<h4 id='beans-factory-instantiation'>容器實(shí)例化</h4>
Spring IoC的實(shí)例化易如反掌。ApplicationContext構(gòu)造函數(shù)支持定位路徑,定位路徑也可以是多個(gè),它是標(biāo)識實(shí)際資源的字串,容器使用該標(biāo)識加載配置元數(shù)據(jù),支持多種資源,比如:本地文件系統(tǒng)、CLASSPATH等等。

    ApplicationContext context = 
        new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});  

注意

在學(xué)習(xí)了Spring IoC容器之后,也許你想了解更多的Spring的資源,如前所述在第6章,資源使用URI語法定位輸入流,Spring提供了方便的機(jī)制讀取輸入流。在第6.7章“Application contexts and Resource paths”,專門講述5用 資源路徑構(gòu)造應(yīng)用上下文,資源路徑也是慣用手法。
接下來的樣例展示了配置service層對象:

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

    <!-- services -->

    <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
    <property name="accountDao" ref="accountDao"/>
    <property name="itemDao" ref="itemDao"/>
    <!-- 有關(guān)屬性配置 -->
    </bean>

    <!--更多的Service bean -->

</beans>

下面的樣例展示了數(shù)據(jù)訪問對象dao.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">

    <bean id="accountDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
    <!-- additional collaborators and configuration for this bean go here -->
    </bean>
    
    <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
    <!-- additional collaborators and configuration for this bean go here -->
    </bean>
    
    <!-- more bean definitions for data access objects go here -->
</beans>

上述內(nèi)容中service層由PetStoreServiceImpl類、2個(gè)dao對象JpaAccountDaoJpaItemDao(基于JPA ORM標(biāo)準(zhǔn))。屬性name元素引用了JavaBean的屬性,ref元素引用了其他bean定義。這個(gè)引用表示實(shí)際對象之間的引用依賴。配置一個(gè)對象的依賴,詳情請參看Dependencies

<h5 id='beans-factory-xml-import'>引入基于xml的元數(shù)據(jù)</h5>
多個(gè)配置文件共同定義bean非常有用。通常,每個(gè)XML配置文件在你的架構(gòu)中代表一個(gè)邏輯層或者一個(gè)模塊。

你可以使用應(yīng)用上下文(applicationContext)的構(gòu)造函數(shù)去加載所有xml中定義的bean。這個(gè)構(gòu)造函數(shù)使用多個(gè)資源定位,就像前面中提到的。或者,也可以用一個(gè)或者多個(gè)資源引用,即使用<import/>標(biāo)簽加載其他文件定義的bean。舉個(gè)栗子:

    <beans>
        <import resource="services.xml"/>
        <import resource="resources/messageSource.xml"/>
        <import resource="/resources/themeSource.xml"/>
        
        <bean id="bean1" class="..."/>
        <bean id="bean2" class="..."/>
    </beans>

上例中,從三個(gè)外部文件加載定義的bean:services.xml,messageSource.xml,themeSource.xml 。被引入的文件的路徑對于引入配置文件來說都是相對路徑,所以service.xml必須在引入配置文件的相同文件路徑或者相同的類路徑中。而messageSource.xmlthemeSource.xml必須在引入配置文件所在的文件夾下的resouce文件夾下。正如你所看到的 /開頭會被忽略掉,因?yàn)檫@些路徑是相對路徑,推薦不要使用/開頭的格式。導(dǎo)入(imported)文件內(nèi)容,包含根節(jié)點(diǎn)<beans/>,配置中XML bean定義 必須經(jīng)過Spring語法校驗(yàn)通過。

注意

使用"../"表示父目錄的相對路徑是可以的,但是真心不推薦這樣創(chuàng)建一個(gè)依賴應(yīng)用外部文件的做法。尤其指出,使用"classpath:"資源類型的URLs(像這樣:"classpath:../services.xml"),也是不推薦的,因?yàn)檫\(yùn)行時(shí)處理過程會選擇"最近的"根路徑然后引入他的父目錄配置文件。Classpath配置的改變,會導(dǎo)致應(yīng)用選擇一個(gè)不同的、錯(cuò)誤的目錄。
你可以使用全路徑限定資源定位取代相對路徑,比如:"file:C:/config/services.xml" 或者"classpath:/config/services.xml"。還有,你可以使用抽象路徑來解耦應(yīng)用和配置文件。使用一個(gè)邏輯定位更可取 ,比如:通過"${..}"占位符,使用JVM運(yùn)行時(shí)計(jì)算出的路徑。

<h4 id='beans-factory-client'>使用容器</h4>
ApplicationContext是一個(gè)高級工廠的接口,能維護(hù)各種bean以及他們之間依賴的注冊。使用方法T getBean(String name, Class<T> requiredType),就能從定義的bean中獲取實(shí)例。
ApplicationContext能讓你讀取bean定義、訪問他們,如下:

// create and configure beans
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});

// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// use configured instance
List<String> userList = service.getUsernameList();  

使用getBean()從beans中獲取實(shí)例。ApplicationContext接口有幾種方法可以辦到,但是理想的做法是不要使用他們。實(shí)際上,應(yīng)用中根本就不該使用getBean()方法,這樣就不依賴Sprig API了。比如,Spring集成了很多web框架,為各種web框架類提供了依賴注入,比如web框架的Controller和JSF-managed beans

<h3 id='beans-definition'>Bean概述</h3>
Spring IoC容器管理一個(gè)或多個(gè)bean。這些bean根據(jù)提供給容器的配置元數(shù)據(jù)創(chuàng)建的,比如使用XML格式<bean/>定義。
在容器內(nèi)部,這些bean的定義用 BeanDefinition對象表示,BeanDefinition包含了下列元數(shù)據(jù):

  • 全路徑(含包路徑)類名:代表bean的實(shí)際實(shí)現(xiàn)類。
  • Bean行為配置元素,它規(guī)定了bean在容器中行為(作用域,生命周期回調(diào)函數(shù)等等)
  • 引用其他bean,就是為了bean能正常工作而所需的其他bean的引用。這些引用類也稱為合作類或者依賴類。
  • 其他配置,為實(shí)例設(shè)置的其他屬性配置。比如說,管理連接池的bean的連接數(shù),池大小的上限。

這些元數(shù)據(jù)將轉(zhuǎn)換成bean定義(BeanDefinition類)的屬性。

The bean definition

屬性 詳情
class Section 5.3.2, “Instantiating beans”
name Section 5.3.1, “Naming beans”
scope Section 5.5, “Bean scopes”
constructor arguments Section 5.4.1, “Dependency injection”
properties Section 5.4.1, “Dependency injection”
autowiring mode Section 5.4.5, “Autowiring collaborators”
lazy-initialization mode Section 5.4.4, “Lazy-initialized beans”
initialization method the section called “Initialization callbacks”
destruction method the section called “Destruction callbacks”

除了bean的信息以外,BeanDefinition也包含創(chuàng)建特殊bean的信息,ApplicationContext的實(shí)現(xiàn)也允許注冊由用戶創(chuàng)建而非IoC容器創(chuàng)建的對象。通過訪問ApplicationContext’s BeanFactory的方法getBeanFactory(),該方法返回BeanFactory的實(shí)現(xiàn)DefaultListableBeanFactory。DefaultListableBeanFactory類支持這種注冊,通過registerSingleton(..)registerBeanDefinition(..)方法實(shí)現(xiàn)。然而,典型的應(yīng)用只用元數(shù)據(jù)定義的bean就可以單獨(dú)運(yùn)行。

<h4 id='beans-beanname'>beans命名</h4>
bean有一個(gè)或者多個(gè)標(biāo)示符。這些標(biāo)示符必須是所在容器范圍內(nèi)必唯一的。通常情況一下,一個(gè)bean僅有一個(gè)標(biāo)示符,如果有需求需要多個(gè),多出來的將被當(dāng)做別名。

在XML格式配置元數(shù)據(jù)中,使用 id 或者 name 屬性來作為bean的標(biāo)示符。id屬性只能有1個(gè)。命名規(guī)范是字符數(shù)字混編(myBean,fooService,等等),但也支持特殊字符,可以包含。若想給bean起個(gè)別名,則可使用name屬性來指定,可以是多個(gè),用英文的逗號(,)分隔、分號(;)也行、空格也行。注意,在Spring3.1以前,id屬性定義成了xsd:ID類型,該類型強(qiáng)制為字符(譯者心里說:估計(jì)字母+特殊字符,不支持?jǐn)?shù)字的意思,有待驗(yàn)證,沒工夫驗(yàn)證去了,翻譯進(jìn)度太慢了。再說了,現(xiàn)在都用4了,你再說3.0怎么著怎么著,那不跟孔乙己似的跟別人吹噓茴香豆有四種寫法)。3.1版開始,它被定義為xsd:string類型。注意,bean id的唯一性約束依然被容器強(qiáng)制使用,盡管xml解析器不再支持了。譯者注:在spring3(含)以前,id是可以相同的,容器會替換相同id的bean,而在新版中,容器初始化過程中發(fā)現(xiàn)id相同拋出異常,停止實(shí)例化

idname屬性不是bean所必須的。若未明確指定id或者name屬性,容器會給它生成一個(gè)唯一name屬性。當(dāng)然了,如果你想通過bean的name屬性引用,使用ref元素方式,或者是類似于Service Locator模式方式檢索bean(譯者想:應(yīng)該是指調(diào)用ApplicationContext.getBean()方法獲取bean,類似這種方式。Service Locator是一種設(shè)計(jì)模式,其實(shí)換個(gè)名字是不是更合適,DL(Dependency Lookup依賴查找)。雖然現(xiàn)在我也不明白,但是下面有專門的章節(jié)講解,翻到時(shí)候再詳細(xì)了解),就必須給bean指定 name了。之所以支持無name bean特性,是為了使內(nèi)部類自動裝配。

Bean命名規(guī)范

bean命名規(guī)范使用java命名規(guī)范中實(shí)例屬性名(也稱域,F(xiàn)ield)規(guī)范。小寫字母開頭的駝峰式。像這樣
(不包括單引號)`accountManager`,`accountService`,`userDao`,
`loginController`,等等

規(guī)范的命名使配置易讀易理解。若使用Spring AOP,通過名字增強(qiáng)(譯注:大多數(shù)Spring AOP教材中
的 通知)一坨bean時(shí),規(guī)范的命名將帶來極大的方便。

<h5 id='beans-beanname-alias'>bean定義之外設(shè)置別名</h5>
定義的bean內(nèi),可以給bean多個(gè)標(biāo)識符,組合id屬性值和任意數(shù)量的name屬性值。這些標(biāo)識符均可作為該bean的別名,對于有些場景中,別名機(jī)制非常有用,比如應(yīng)用中組件對自身的引用。(譯注:一個(gè)類持有一個(gè)本類的實(shí)例作為屬性,看起來應(yīng)該是這樣的,以下代碼為推測,可以執(zhí)行)
Bean類

public class SomeBean {
    //注意看這個(gè)屬性,就是本類
    private SomeBean someBean;
    
    public SomeBean(){}
    
    public void setSomeBean(SomeBean someBean) {
        this.someBean = someBean;
    }
}

配置元數(shù)據(jù)

<?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的別名,使用,/;/空格 分隔都是可以是-->
    <bean id="someBeanId" name="someBean,someBeanA;someBeanB someBeanC" class="com.example.spring.bean.SomeBean">
        <!--將別名為someBeanA 的bean 注入給 id為someBeanId 的bean的屬性 'someBean'-->
        <property name="someBean" ref="someBeanA"></property>
    </bean>
</beans>

測試代碼

@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class SomeBeanTests {
    
    @Autowired
    @Qualifier("someBeanId")
    private SomeBean someBean;
    
    @Test
    public void testSimpleProperties() throws Exception {
    }
    
}

在bean的定義處指定所有別名有時(shí)候并不合適,然而,在其他配置文件中給bean設(shè)置別名卻更為恰當(dāng)。此法通常應(yīng)用在大型系統(tǒng)的場景中,配置文件分散在各個(gè)子系統(tǒng)中,每個(gè)子系統(tǒng)都有本系統(tǒng)的bean定義。XML格式配置元數(shù)據(jù),提供<alias/>元素,可以搞定此用法。

<alias name="fromName" alias="toName"/>

這種情況下,在同容器中有個(gè)叫fromName的bean,或者叫其他的阿貓阿狗之類的,再使用此別名定義之后,即可被當(dāng)做toName來引用。

舉個(gè)栗子,子系統(tǒng)A中的配置元數(shù)據(jù)也許引用了一個(gè)被命名為subsystemA-dataSource的bean。子系統(tǒng)B也許引用了一個(gè)subsystemB-dataSource。將這兩個(gè)子系統(tǒng)整合到主應(yīng)用中,而主應(yīng)用使用了一個(gè)myApp-dataSource,為了使3個(gè)bean引用同一個(gè)對象,得在MyApp配置元數(shù)據(jù)中使用別名定義:

<alias name="subsystemA-dataSource" alias="subsystemB-dataSource"/>
<alias name="subsystemA-dataSource" alias="myApp-dataSource" />

現(xiàn)在,每個(gè)組件和主應(yīng)用都能通過bean 名引用dataSource,而bean名都是唯一的保證不與其他定義沖突(實(shí)際上創(chuàng)建了一個(gè)命名空間),但他們引用的都是同一個(gè)bean。

Java-configuration

如果你使用了Java-configuration@Bean注解也提供了別名,詳見Section 5.12.3, “Using the @Bean annotation”

<h4 id='beans-factory-class'>bean實(shí)例化</h4>
bean的定義,本質(zhì)是如何創(chuàng)建一個(gè)或多個(gè)對象的配方。容器被請求時(shí),會解析配置元數(shù)據(jù)中的bean定義并封裝,使用封裝配置創(chuàng)建(或者獲?。ο髮?shí)例。

若使用XML格式配置元數(shù)據(jù),得為將要實(shí)例化的對象指定類型(或者說是類),使用<bean/>元素的class屬性實(shí)現(xiàn)。class屬性 映射到BeanDefinition類實(shí)例的Class屬性(域),這個(gè)class屬性是<bean/>元素必須的。(例外情況,參看“Instantiation using an instance factory method”Section 5.7, “Bean definition inheritance”。使用Class域?qū)傩?,通過以下兩種方式:

  • 通常,通過指定bean的class 屬性,容器使用反射調(diào)用其構(gòu)造函數(shù)直接創(chuàng)建bean,有點(diǎn)像Java 編碼中使用new操作符。
  • 指定class實(shí)際類含有用于創(chuàng)建對象的靜態(tài)工廠方法,這是不常使用的場景,容器會調(diào)用類的靜態(tài)工廠方法創(chuàng)建bean。調(diào)用靜態(tài)工廠方法返回的對象類型也許是相同類型,也許完全是其他類。

<div class="sidebar">
<b>內(nèi)部類命名</b> 若要定義靜態(tài)內(nèi)部類,得將類名劈開。


舉例來說,現(xiàn)在在<span class="scode">com.example</span>包有個(gè)類<span class="scode">Foo</span>,該類有靜態(tài)內(nèi)部類<span class="scode">Bar</span>,定義<span class="scode">Bar</span>的Spring bean的<span class="scode">class</span>屬性差不多是這樣


<code class="scode">com.example.Foo$Bar</code>



注意<span class="scode">$</span>字符,用它來分隔內(nèi)部類名和外圍類名
</div>

<h4 id='beans-factory-class-ctor'>用構(gòu)造函數(shù)實(shí)例化</h4>
若是使用構(gòu)造函數(shù)方式創(chuàng)建bean,所有的常規(guī)類都可以使用Spring來創(chuàng)建、管理。也就是說,開發(fā)的類無需實(shí)現(xiàn)任何特殊接口或者使用某種特殊編碼風(fēng)格。僅需指定bean的class即可。對于特殊的bean管理,取決于你使用的IoC類型,也許需要一個(gè)默認(rèn)的空構(gòu)造。

Spring IoC容器幾乎能管理任何你需要管理的類,不局限于真正的JavaBeans。大多數(shù)Spring的用戶心中,真正的JavaBean是這樣的:僅有1個(gè)默認(rèn)的無參構(gòu)造函數(shù)、屬性、setter、getter。嗯,比如,現(xiàn)在需要使用一個(gè)廢棄連接池,它肯定不符合JavaBean規(guī)范,Spring照樣能管理。

使用XML格式配置元數(shù)據(jù) 定義bean的class,如下所示:

<bean id="exampleBean" class="examples.ExampleBean"/>

<bean name="anotherExample" class="examples.ExampleBeanTwo"/>  

如何為構(gòu)造函數(shù)指定參數(shù)?如何在對象實(shí)力話之后設(shè)置其屬性?請參看Injecting Dependencies

<h5 id='beans-factory-class-static-factory-method'>使用靜態(tài)工廠方法實(shí)例化</h5>
定義使用使用靜態(tài)工廠方法創(chuàng)建的bean時(shí),得指定工廠方法類的作為class屬性值,并且還得指定工廠方法類中用于創(chuàng)建bean的方法名稱,作為factory-method屬性值。工廠方法可以有參數(shù),調(diào)用該方法即可返回對象實(shí)例,就像通過構(gòu)造函數(shù)創(chuàng)建對象實(shí)例一樣。此種bean定義是為了兼容遺留系統(tǒng)中的靜態(tài)工廠

下面的bean定義,是使用工廠方法創(chuàng)建bean的方式。定義中,無需指定返回對象的類型(class),而是指定工廠方法類的class。下例中,createInstance()方法必須是一個(gè)static靜態(tài)方法。

<bean id="clientService"
    class="examples.ClientService"
    factory-method="createInstance"/>  

繼續(xù)

public class ClientService {
    private static ClientService clientService = new ClientService();
    private ClientService() {}
    
    public static ClientService createInstance() {
    return clientService;
    }
}   

<h5 id='beans-factory-class-instance-factory-method'>使用實(shí)例工廠方法實(shí)例化</h5>
靜態(tài)工廠方法類似的還有實(shí)例工廠方法,使用實(shí)例工廠方法的方式實(shí)例化,是調(diào)用容器中已存在的bean的一個(gè)非靜態(tài)方法來創(chuàng)建一個(gè)bean。用法是,1、class屬性置空設(shè)置。 2、設(shè)置factory-bean屬性,其值為當(dāng)前容器(或者父容器)中bean的名字,該bean包含可供調(diào)用的創(chuàng)建對象的實(shí)例方法。3、設(shè)置factory-method屬性,其值為工廠方法名。

<!-- 工廠類, 包含一個(gè)方法createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>

<!-- the bean to be created via the factory bean -->
<bean id="clientService"
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>

工廠類如下

public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();
    private DefaultServiceLocator() {}
    
    public ClientService createClientServiceInstance() {
    return clientService;
    }
}

工廠類可以有多個(gè)工廠方法:

<bean id="serviceLocator" class="examples.DefaultServiceLocator">
    <!-- inject any dependencies required by this locator bean -->
</bean>

<bean id="clientService"
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>

<bean id="accountService"
    factory-bean="serviceLocator"
    factory-method="createAccountServiceInstance"/>

工廠類如下:

public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();
    private static AccountService accountService = new AccountServiceImpl();

    private DefaultServiceLocator() {}

    public ClientService createClientServiceInstance() {
        return clientService;
    }

    public AccountService createAccountServiceInstance() {
        return accountService;
    }

}

上例中展示了工廠類本身也可以通過 DI 管理和配置。參看DI詳情

注意

Srping 資料中,factory bean是指一個(gè)Spring配置的bean,該bean能通過實(shí)例或者靜態(tài)工廠方法創(chuàng)建對象。對比之下,FactoryBean(注意大寫)是指Spring術(shù)語FactoryBean。這段沒太理解,解釋factory bean和FactoryBean。

<h3 id='beans-dependencies'>依賴</h3>
企業(yè)應(yīng)用絕不會只有1個(gè)簡單對象(或者說Spring bean)。哪怕是最簡單的應(yīng)用,也會包含許多對象協(xié)同工作。下一章節(jié)講述,如何為真正的應(yīng)用定義大量的、獨(dú)立的bean,并讓這些對象一起合作。

<h4 id="beans-factory-collaborators">依賴注入</h4>
依賴注入(DI),是一個(gè)有對象定義依賴的手法,也就是,如何與其他對象合作,通過構(gòu)造參數(shù)、工廠方法參數(shù)、或是在對象實(shí)例化之后設(shè)置對象屬性,實(shí)例化既可以構(gòu)造也可以是使用工廠方法。容器在它創(chuàng)建bean之后注入依賴。這個(gè)過程從根本上發(fā)生了反轉(zhuǎn),因此又名控制反轉(zhuǎn)(Ioc),因?yàn)镾pring bean自己控制依賴類的實(shí)例化或者定位 ,Spring bean中就有依賴類的定義,容器使用依賴類構(gòu)造器創(chuàng)建依賴類實(shí)例,使用Service Locator模式定位依賴類。

DI機(jī)制使代碼簡潔,對象提供它們的依賴,解耦更高效。對象無需自己查找依賴。同樣的,類更容易測試,尤其當(dāng)依賴接口或者抽象類時(shí),測試允許在單元測試中使用stub或者mock(模擬技術(shù))實(shí)現(xiàn)。

DI有2種主要方式,構(gòu)造注入setter注入
構(gòu)造注入,容器調(diào)用構(gòu)造函數(shù)并傳參數(shù),每個(gè)參數(shù)都是依賴。調(diào)用靜態(tài)工廠方法并傳參數(shù)方式構(gòu)造bean和構(gòu)造注入差不多,這里是指構(gòu)造注入處理參數(shù)和靜態(tài)工廠方法處理參數(shù)像類似。下例中展示了一個(gè)只能使用構(gòu)造注入的類。注意,此類無任何特別之處,并未依賴容器指定的接口、基類、注解,就是一個(gè)POJO

public class SimpleMovieLister {

    // the SimpleMovieLister 依賴 a MovieFinder
    private MovieFinder movieFinder;

    //Spring容器能注入MovieFinder的構(gòu)造函數(shù)
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // 實(shí)際如何使用MovieFinder的業(yè)務(wù)邏輯省略了

}

<h5 id='beans-factory-ctor-arguments-resolution'>構(gòu)造函數(shù)參數(shù)解決方案</h5>
構(gòu)造參數(shù)解決方案,會匹配所使用的參數(shù)類型。如果在bean的定義中,構(gòu)造參數(shù)不存在歧義,那么,在bean定義中定義的構(gòu)造參數(shù)的次序,在bean實(shí)例化時(shí),就是提供給適合的構(gòu)造參數(shù)的次序??催@個(gè)類:

package x.y;

public class Foo {

    public Foo(Bar bar, Baz baz) {
        // ...
    }

}

不存在歧義,假設(shè)BarBaz類沒有集成關(guān)系,那么下面的配置是合法的,而且,不需要在<constructor-arg/>元素里指定構(gòu)造參數(shù)的明確的indexes索引或者類型。

<beans>
    <bean id="foo" class="x.y.Foo">
        <constructor-arg ref="bar"/>
        <constructor-arg ref="baz"/>
    </bean>

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

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

若需要引用另一個(gè)bean,類型已知,構(gòu)造函數(shù)就可以匹配參數(shù)類型(像上面的示例)。使用簡單類型時(shí), 想<value>true</true>,Srping不能決定value類型情況,Spring就不能自己匹配類型。例如:

package examples;

public class ExampleBean {

    // Number of years to calculate the Ultimate Answer
    private int years;

    // The Answer to Life, the Universe, and Everything
    private String ultimateAnswer;

    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }

}

上面的場景中,如果使用type屬性明確指定構(gòu)造參數(shù)的類型,容器就可以使用類型匹配。比如:

    <bean id="exampleBean" class="examples.ExampleBean">
        <constructor-arg type="int" value="7500000"/>
        <constructor-arg type="java.lang.String" value="42"/>
    </bean>

使用index屬性明確指定構(gòu)造參數(shù)的次序。比如

    <bean id="exampleBean" class="examples.ExampleBean">
        <constructor-arg index="0" value="7500000"/>
        <constructor-arg index="1" value="42"/>
    </bean>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 參考W3C Spring教程 Spring致力于J2EE應(yīng)用的各種解決方案,而不僅僅專注于某一層解決方案。可以說S...
    王偵閱讀 1,234評論 0 6
  • 開始使用Spring Framework 5.0和設(shè)計(jì)模式 介紹Spring框架 Spring簡化了應(yīng)用程序開發(fā),...
    一顆懶能閱讀 2,990評論 3 21
  • 2.1 我們的理念是:讓別人為你服務(wù) IoC是隨著近年來輕量級容器(Lightweight Container)的...
    好好學(xué)習(xí)Sun閱讀 2,868評論 0 11
  • 今天又單獨(dú)把周重林的書拿出來看了一遍,看了三分之一。我發(fā)現(xiàn)我確實(shí)是書要看2遍才有印象,每次看的時(shí)候收獲都不一樣,然...
    茶女子張怡閱讀 165評論 0 0
  • 等許桑再見到蘇軒時(shí)已經(jīng)是一個(gè)月以后了。籃球在籃球框邊懸搖轉(zhuǎn)動,蘇軒騰空的身子落地?!鞍““ 彪S著女生瘋狂的尖叫...
    憶夕笑雪閱讀 323評論 0 0

友情鏈接更多精彩內(nèi)容