Spring基本原理 - 容器和bean

Spring IoC容器至少包含一個bean定義,但大多數狀況下會有多個bean定義。當使用 基於XML的配置元數據時,將在頂層的<beans/>元素中配置一個 或多個<bean/>元素。spring

bean定義與應用程序中實際使用的對象一一對應。一般狀況下bean的定義包括:服務 層對象、數據訪問層對象(DAO)、相似Struts Action的 表示層對象、Hibernate SessionFactory對象、JMS Queue對象等等。一般bean的定義並不與容器中的領域 對象相同,由於領域對象的建立和加載必須依賴具體的DAO和業務邏輯。.數組

1.如下是一個基於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-2.5.xsd">

  <bean id="..." class="...">
    <!-- collaborators and configuration for this bean go here -->
  </bean>

  <bean id="..." class="...">
    <!-- collaborators and configuration for this bean go here -->
  </bean>

  <!-- more bean definitions go here -->

</beans>

2.實例化容器

Spring IoC容器的實例化很是簡單,以下面的例子:ui

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

// an  is also a  (via inheritance)
BeanFactory factory = context;ApplicationContextBeanFactory

3. XML配置元數據的結構

將XML配置文件分拆成多個部分是很是有用的。爲了加載多個XML文件生成一個 ApplicationContext實例,能夠將文件路徑做爲字符串數組傳給ApplicationContext構造器 。而bean factory將經過調用bean defintion reader從多個文件中讀取bean定義。this

一般狀況下,Spring團隊傾向於上述作法,由於這樣各個配置並不會查覺到它們 與其餘配置文件的組合。另一種方法是使用一個或多個的<import/>元素 來從另一個或多個文件加載bean定義。全部的<import/>元素必 須在<bean/>元素以前完成bean定義的導入。 讓咱們看個例子:編碼

<beans>

    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>

    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>

</beans>

在上面的例子中,咱們從3個外部文件:services.xmlmessageSource.xmlthemeSource.xml 來加載bean定義。這裏採用的都是相對路徑,所以,此例中的services.xml 必定要與導入文件放在同一目錄或類路徑,而messageSource.xm lthemeSource.xml的文件位置必須放在導入文件所 在目錄下的resources目錄中。正如你所看到的那樣,開頭的斜槓 ‘/’實際上可忽略。所以不用斜槓‘/’可能會更好一點。根據Spring XML配置文件的 Schema(或DTD),被導入文件必須是徹底有效的XML bean定義文件,且根節點必須爲 <beans/> 元素。spa

4.多種bean

Spring IoC容器將管理一個或多個bean,這些bean 將經過配置文件中的bean定義被建立(在XML格式中爲<bean/> 元素)。翻譯

在容器內部,這些bean定義由BeanDefinition 對象來表示,該定義將包含如下信息:code

  • 全限定類名:這一般就是已定義bean的實際實現類。component

  • bean行爲的定義,這些定義將決定bean在容器中的行爲(做用域、生命週期回調等等)

  • 對其餘bean的引用,這些引用bean也能夠稱之爲協做bean(collaborators) 依賴bean(dependencies).

  • 建立bean實例時的其餘配置設置。好比使用bean來定義鏈接池,能夠經過屬性或者構 造參數指定鏈接數,以及鏈接池大小限制等。

上述內容直接被翻譯爲每一個bean定義包含的一組properties。下面的表格列出了部分 內容的詳細連接:

5.表  bean定義

名稱 功能
class

 「實例化bean」

name

 「bean的命名」

scope

 「Bean的做用域」

constructor arguments

「注入依賴」

properties

 「注入依賴」

autowiring mode

 「自動裝配(autowire)協做者」

dependency checking mode

 「依賴檢查」

lazy-initialization mode

「延遲初始化bean」

initialization method

「初始化回調」

destruction method

 「析構回調」

 

除了經過bean定義來描述要建立的指定bean的屬性以外,某些 BeanFactory的實現也容許將那些非BeanFactory建立的、已有的用戶 對象註冊到容器中,好比使用DefaultListableBeanFactoryregisterSingleton(..) 方法。不過大多數應用仍是採用 元數據定義爲主。

6. bean的命名

bean命名約定

bean的命名採用標準的Java命名約定,即小寫字母開頭,首字母大寫間隔 的命名方式。如accountManageraccountService userDaologinController,等等。

對bean採用統一的命名約定將會使配置更加簡單易懂。並且在使用Spring AOP時 ,若是要發通知(advice)給與一組名稱相關的bean時,這種簡單的命名方式將會令你受益不淺。

每一個bean都有一個或多個id(或稱之爲標識符或名稱,在術語 上能夠理解成一回事)。這些id在當前IoC容器中必須惟一。若是 一個bean有多個id,那麼其餘的id在本質上將被認爲是別名。

當使用基於XML的配置元數據時,將經過id name屬性來指定bean標識符。id屬性具備惟一性, 並且是一個真正的XML ID屬性,所以其餘xml元素在引用該id時,能夠利用XML解析器的 驗證功能。一般狀況下最好爲bean指定一個id。儘管XML規範規定了XML ID命名的有效 字符,可是bean標識符的定義不受該限制,由於除了使用指定的XML字符來做爲id,還可 覺得bean指定別名,要實現這一點能夠在name屬性中使用逗號、 冒號或者空格將多個id分隔。

值得注意的是,爲一個bean提供一個name並非必須的,若是沒有指定,那麼容 器將爲其生成一個唯一的name。對於不指定name屬性的緣由咱們會在後面介紹(好比 內部bean就不須要)。

3.2.3.1.1. bean的別名

在對bean進行定義時,除了使用id屬性來指定名稱 以外,爲了提供多個名稱,須要經過name屬性來加以指定 。而全部的這些名稱都指向同一個bean,在某些狀況下提供別名很是有用,好比 爲了讓應用的每個組件能更容易的對公共組件進行引用。

然而,在定義bean時就指定全部的別名並非老是恰當的。有時咱們指望 能在當前位置爲那些在別處定義的bean引入別名。在XML配置文件中,可用 <alias/> 元素來完成bean別名的定義。如:

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

這裏若是在容器中存在名爲fromName的bean定義, 在增長別名定義以後,也能夠用toName來引用。

考慮一個更爲具體的例子,組件A在XML配置文件中定義了一個名爲 componentA-dataSource的DataSource bean。但組件B卻想在其XML文件中 以componentB-dataSource的名字來引用此bean。並且在主程序MyApp的XML配 置文件中,但願以myApp-dataSource的名字來引用此bean。最後容器加載三個 XML文件來生成最終的ApplicationContext,在此情形下,可經過在MyApp XML 文件中添加下列alias元素來實現:

<alias name="componentA-dataSource" alias="componentB-dataSource"/>
<alias name="componentA-dataSource" alias="myApp-dataSource" />

這樣一來,每一個組件及主程序就可經過惟一名字來引用同一個數據源而互不干擾。

7. 實例化bean

內部類名

若是須要你但願將一個靜態的內部類配置爲 一個bean的話,那麼內部類的名字須要採用二進制的寫法。

好比說,在com.example包下有一個叫 Foo的類,而Foo類有一個靜態 的內部類叫Bar,那麼在bean定義的時候, class屬性必須這樣寫:

com.example.Foo$Bar

注意這裏咱們使用了$字符將內部類和外部類進行分隔

從本質上來講,bean定義描述瞭如何建立一個或多個對象實例。當須要的時候, 容器會從bean定義列表中取得一個指定的bean定義,並根據bean定義裏面的配置元數據 使用反射機制來建立(或取得)一個實際的對象。

當採用XML描述配置元數據時,將經過<bean/>元素的 class屬性來指定實例化對象的類型。class 屬性 (對應BeanDefinition實例的 Class屬性)一般是必須的(不過也有兩種例外的情形,「使用實例工廠方法實例化」「bean定義的繼承」)。class屬性主要有兩種用途 :在大多數狀況下,容器將直接經過反射調用指定類的構造器來建立bean(這有點相似於 在Java代碼中使用new操做符);在極少數狀況下,容器將調用 類的靜態工廠方法來建立bean實例,class 屬性將用來指定實際具備靜態工廠方法的類(至於調用靜態工廠 方法建立的對象類型是當前class仍是其餘的class則可有可無)。

8. 用構造器來實例化

當採用構造器來建立bean實例時,Spring對class並無特殊的要求, 咱們一般使用的class都適用。也就是說,被建立的類並不須要實現任何特定的 接口,或以特定的方式編碼,只要指定bean的class屬性便可。不過根據所採用 的IoC類型,class可能須要一個默認的空構造器。

此外,IoC容器不只限於管理JavaBean,它能夠管理任意 的類。不過大多數使用Spring的人喜歡使用實際的JavaBean(具備默認的(無參)構造器 及setter和getter方法),但在容器中使用非bean形式(non-bean style)的類也是可 以的。好比遺留系統中的鏈接池,很顯然它與JavaBean規範不符,但Spring也能管理它。

當使用基於XML的元數據配置文件,能夠這樣來指定bean類:

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

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

給構造函數指定參數以及爲bean實例設置屬性將在隨後的 部分中談及。

9. 使用靜態工廠方法實例化

當採用靜態工廠方法建立bean時,除了須要指定class 屬性外,還須要經過factory-method屬性來指定建立bean實例 的工廠方法。Spring將調用此方法(其可選參數接下來介紹)返回實例對象,就此而言, 跟經過普通構造器建立類實例沒什麼兩樣。

下面的bean定義展現瞭如何經過工廠方法來建立bean實例。注意,此定義並 未指定返回對象的類型,僅指定該類包含的工廠方法。在此例中, createInstance()必須是一個static方法。

<bean id="exampleBean"
      class="examples.ExampleBean2"
      factory-method="createInstance"/>

給工廠方法指定參數以及爲bean實例設置屬性將在隨後的部份中談及。

10. 使用實例工廠方法實例化

使用靜態工廠方法實例化相似,用來進行實例化的非靜態實例工廠方法位 於另一個bean中,容器將調用該bean的工廠方法來建立一個新的bean實例。爲使 用此機制,class屬性必須爲空,而factory-bean 屬性必須指定爲當前(或其祖先)容器中包含工廠方法的bean的名稱,而該 工廠bean的工廠方法自己必須經過factory-method屬性來設定。

<!-- the factory bean, which contains a method called  -->
<bean id="serviceLocator" class="com.foo.DefaultServiceLocator">
  <!-- inject any dependencies required by this locator bean -->
</bean>

<!-- the bean to be created via the factory bean -->
<bean id="exampleBean"
      factory-bean="serviceLocator"
      factory-method="createInstance"/>createInstance()

雖然設置bean屬性 的機制仍然在這裏被說起,但隱式的作法是由工廠bean本身來管理以及經過依 賴注入(DI)來進行配置。

注意

Spring文檔中的factory bean指的是配置在Spring容器中經過使用 實例 靜態工廠方法建立對象的一種bean。而文檔中的FactoryBean (注意首字母大寫)指的是Spring特有的 FactoryBean

11. 使用容器

從本質上講,BeanFactory僅僅只是一個 維護bean定義以及相互依賴關係的高級工廠接口。經過BeanFactory 咱們能夠訪問bean定義。下面的例子建立了一個bean工廠,此工廠 將從xml文件中讀取bean定義:

Resource res = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(res);

基本上就這些了,接着使用getBean(String) 方法就能夠取得bean的實例;BeanFactory 提供的方法極其簡單。 BeanFactory接口提供 了很是多的方法,可是對於咱們的應用來講,最好永遠不要調用它們,固然也包括 使用getBean(String)方法,這樣能夠避免咱們對 Spring API的依賴。

相關文章
相關標籤/搜索