Spring中ApplicationContext和beanfactory區別

org.springframework.beansorg.springframework.context包是Spring IoC容器的基礎。BeanFactory提供的高級配置機制,使得管理任何性質的對象成爲可能。ApplicationContextBeanFactory的擴展,功能獲得了進一步加強,好比更易與Spring AOP集成、消息資源處理(國際化處理)、事件傳遞及各類不一樣應用層的context實現(如針對web應用的WebApplicationContext)。html

簡而言之,BeanFactory提供了配製框架及基本功能,而ApplicationContext則增長了更多支持企業核心內容的功能。ApplicationContext徹底由BeanFactory擴展而來,於是BeanFactory所具有的能力和行爲也適用於ApplicationContextweb

org.springframework.beans.factory.BeanFactory是Spring IoC容器的實際表明者,IoC容器負責容納此前所描述的bean,並對bean進行管理。spring

在Spring中,BeanFactory是IoC容器的核心接口。它的職責包括:實例化、定位、配置應用程序中的對象及創建這些對象間的依賴。api

Spring爲咱們提供了許多易用的BeanFactory實現,XmlBeanFactory就是最經常使用的一個。該實現將以XML方式描述組成應用的對象以及對象間的依賴關係。XmlBeanFactory類將持有此XML配置元數據,並用它來構建一個徹底可配置的系統或應用。數組

Spring IoC 容器app

從上圖能夠看到,Spring IoC容器將讀取配置元數據;並經過它對應用中各個對象進行實例化、配置以及組裝。一般狀況下咱們使用簡單直觀的XML來做爲配置元數據的描述格式。在XML配置元數據中咱們能夠對那些咱們但願經過Spring IoC容器管理的bean進行定義框架

在大多數的應用程序中,並不須要用顯式的代碼去實例化一個或多個的Spring IoC容器實例。例如,在web應用程序中,咱們只須要在web.xml中添加(大約)8 行簡單的XML描述符便可。你能夠象下面那樣使用ContextLoaderListener來註冊一個ApplicationContext函數

<context-param>
       <param-name>contextConfigLocation</param-name>
       <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener><!-- or use the ContextLoaderServlet instead of the above listener<servlet>
       <servlet-name>context</servlet-name>
       <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
       <load-on-startup>1</load-on-startup>
</servlet>
-->

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

bean定義與應用程序中實際使用的對象一一對應。一般狀況下bean的定義包括:服務層對象、數據訪問層對象(DAO)、相似Struts Action的表示層對象、Hibernate SessionFactory對象、JMS Queue對象等等。項目的複雜程度將決定bean定義的多寡。this

如下是一個基於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.0.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>
Spring IoC容器的實例化很是簡單,以下面的例子:
Resource resource = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);... 或...ClassPathResource resource 
= new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);... 或...ApplicationContext context 
= new ClassPathXmlApplicationContext(
             new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
// of course, an ApplicationContext is just a BeanFactoryBeanFactory factory 
=(BeanFactory) context;
將XML配置文件分拆成多個部分是很是有用的。
  爲了加載多個XML文件生成一個ApplicationContext實例,能夠將文件路徑做爲字符串數組傳給ApplicationContext
構造器。而bean factory將經過調用bean defintion reader從多個文件中讀取bean定義。一般狀況下,
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.xml、messageSource.xml及themeSource.xml
來加載bean定義。這裏採用的都是相對路徑,所以,此例中的services.xml必定要與導入文件放在同一目錄或類路徑,
而messageSource.xml和themeSource.xml的文件位置必須放在導入文件所在目錄下的resources目錄中。
正如你所看到的那樣,開頭的斜槓‘/’實際上可忽略。所以不用斜槓‘/’可能會更好一點。

  根據Spring XML配置文件的Schema(或DTD),被導入文件必須是徹底有效的XML bean定義文件,
且根節點必須爲<beans/> 元素。誠如此前所言,Spring IoC容器將管理一個或多個bean,
這些bean將經過配置文件中的bean定義被建立(在XML格式中爲<bean/>元素)。
在容器內部,這些bean定義由BeanDefinition 對象來表示,該定義將包含如下信息
:全限定類名:這一般就是已定義bean的實際實現類。若是經過調用static factory方法來實例化bean,
而不是使用常規的構造器,那麼類名稱實際上就是工廠類的類名。bean行爲的定義,即建立模式(prototype仍是
singleton)、自動裝配模式、依賴檢查模式、初始化以及銷燬方法。這些定義將決定bean在容器中的行爲用於
建立bean實例的構造器參數及屬性值。好比使用bean來定義鏈接池,能夠經過屬性或者構造參數指定鏈接數,
以及鏈接池大小限制等。bean之間的關係,即協做 (或者稱依賴)。上述內容直接被翻譯爲每一個bean定義包含的一組
properties除了經過bean定義來描述要建立的指定bean的屬性以外,某些BeanFactory的實現也容許將那些
非BeanFactory建立的、已有的用戶對象註冊到容器中,好比使用DefaultListableBeanFactory的
registerSingleton(..) 方法。

   不過大多數應用仍是採用元數據定義爲主。命名beanbean的命名採用標準的
Java命名約定,即小寫字母開頭,首字母大寫間隔的命名方式。如accountManager、 accountService、
userDao及loginController,等等。
   對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就不須要)。

bean的別名在對bean進行定義時,除了
使用id屬性來指定名稱以外,爲了提供多個名稱,須要經過alias屬性來加以指定。而全部的這些名稱都指向同一個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" />
這樣一來,每一個組件及主程序就可經過惟一名字來引用同一個數據源而互不干擾。

  實例化bean就Spring IoC容器而言,bean定義基本上描述了建立一個或多個實際bean對象的內容。
  當須要的時候,容器會從bean定義列表中取得一個指定的bean定義,並根據bean定義裏面的配置元數據
使用反射機制來建立一個實際的對象。

  所以這一節將講解如何告知Spring IoC容器咱們將要實例化的對象的類型以及如何實例化對象。
  當採用XML描述配置元數據時,將經過<bean/>元素的class屬性來指定實例化對象的類型。class 屬性 (對應
BeanDefinition實例的Class屬性)一般是必須的(不過也有兩種例外的情形)。

  class屬性主要有兩種用途:在大多數狀況下,容器將直接經過反射調用指定類的構造器來
建立bean(這有點等相似於在Java代碼中使用new操做符);
  在極少數狀況下,容器將調用類的靜態工廠方法來建立bean實例,class屬性將用來指定實際具備靜態工廠方法的類
(至於調用靜態工廠方法建立的對象類型是當前class仍是其餘的class則可有可無)。

  用構造器來實例化當採用構造器來建立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實例設置屬性將在隨後的部份中談及。

使用 靜態工廠方法實例化當採用靜態工廠方法建立bean時,除了須要指定class屬性外,
還須要經過factory-method屬性來指定建立bean實例的工廠方法。
Spring將調用此方法(其可選參數接下來介紹)返回實例對象,就此而言,跟經過普通構造器建立類實例沒什麼兩樣。
下面的bean定義展現瞭如何經過工廠方法來建立bean實例。注意,此定義並未指定返回對象的類型,僅指定該類包含的工廠方法。
在此例中, createInstance()必須是一個static方法。
<bean id="exampleBean" class="examples.ExampleBean2" factory-method="createInstance"/>
給工廠方法指定參數以及爲bean實例設置屬性將在隨後的部份中談及。
 使用實例工廠方法實例化與使用靜態工廠方法實例化相似,用來進行實例化的實例工廠方法位於另一個已有的bean中,
容器將調用該bean的工廠方法來建立一個新的bean實例爲使用此機制,class屬性必須爲空,而factory-bean屬性必須
指定爲當前(或其祖先)容器中包含工廠方法的bean的名稱,而該工廠bean的工廠方法自己必須經過factory-method屬性
來設定(參看如下的例子)。
<!-- the factory bean, which contains a method called createInstance() 
--><bean id="myFactoryBean" class="...">
    ...
</bean>
  <!-- the bean to be created via the factory bean --><bean id="exampleBean"
        factory-bean="myFactoryBean"
        factory-method="createInstance"/>
雖然設置bean屬性的機制仍然在這裏被說起,但隱式的作法是由工廠
bean本身來管理以及經過依賴注入(DI)來進行配置。使用容器從本質上講,BeanFactory僅僅只是一個維護bean定義以及
相互依賴關係的高級工廠接口。經過BeanFactory咱們能夠訪問bean定義。
下面的例子建立了一個bean工廠,此工廠將從xml文件中讀取bean定義:
InputStream is = new FileInputStream("beans.xml");
BeanFactory factory = new XmlBeanFactory(is);
 
基本上就這些了,接着使用getBean(String)方法就能夠取得bean的實例;
BeanFactory提供的方法極其簡單。它僅提供了六種方法供客戶代碼調用:
boolean containsBean(String):
若是BeanFactory包含給定名稱的bean定義(或bean實例),則返回
trueObject getBean(String):返回以給定名字註冊的bean實例。

根據bean的配置狀況,若是爲singleton模式將返回一個共享的實例,不然將返回一個新建的實例。
若是沒有找到指定的bean,該方法可能會拋出BeansException異常(實際上將拋出NoSuchBeanDefinitionException異常),

在對bean進行實例化和預處理時也可能拋出異常Object getBean(String, Class):
返回以給定名稱註冊的bean實例,並轉換爲給定class類型的實例,
若是轉換失敗,相應的異常(BeanNotOfRequiredTypeException)將被拋出。
上面的getBean(String)方法也適用該規則。

Class getType(String name):返回給定名稱的bean的Class。
若是沒有找到指定的bean實例,則拋出NoSuchBeanDefinitionException異常。

boolean isSingleton(String):判斷給定名稱的bean定義
(或bean實例)是否爲singleton模式(singleton將在bean的做用域中討論),若是bean沒找到,則
拋出NoSuchBeanDefinitionException異常。

String[] getAliases(String):返回給定bean名稱的全部別名。
相關文章
相關標籤/搜索