Spring參考手冊-第三章 IoC容器-3.2 基本概念-容器和Beans(豆子)

 

爲什麼叫做Bean
使用‘bean’這個名字的原因是因爲在Spring框架中已經使用了‘componet’和‘object’這些基本概念名稱,另外也是由於EJB的複雜性,所以在類似的起了這個名字。
 在Spring裏,組成你應用的核心對象是由IoC容器管理的,被稱作beans。一個bean就是一個實例化的、裝配好的,且由Spring IoC容器管理的對象;除此之外,關於bean沒有什麼其他特別的特性。這些bean以及它們之間的依賴由容器的配置元數據來反映(configuration metadata)。
3.2.1容器
org.springframework.beans.factory.BeanFactorySpring IoC容器的實際界面,它實際負責包含和管理bean
BeanFactory接口是Spring IoC容器的核心。它的作用包括實例化和初始化應用對象,配置對象和組裝對象的依賴。
 有很多BeanFactory的接口實現。最常用的是XmlBeanFactory類,它讓你以XML方式配置組成應用的對象和這些對象間確定的依賴。XmlBeanFactory獲取XML配置元數據並且按照配置來創建一個完整的系統和應用。
Spring IoC容器示意圖
3.2.1.1 配置元數據(Configuration metadata
 從上面的圖片可以看出來,Spring IoC容器使用了一些形式的元數據;配置元數據也就是告訴Spring容器,怎樣實例化,配置和裝配應用對象。配置元數據的形式爲簡單、直觀的XML格式。當使用基於XML的配置元數據時,你需要把那些需要容器管理的bean的定義文件寫好,然後讓容器去做剩下的事情。
注意:
XML基礎的元數據是到目前爲止最常用的配置元數據方式。然後它不是唯一被支持的方式。
Spring容器降低了對於配置元數據的表達格式要求。
在寫配置的時候,你可以以XML、Java數據屬性格式或者編程方式(利用Spring的公共API)來配置文件。然後XML配置方式是相對簡單易用的方式,所以,本章的後面部分將使用XML配置格式來介紹Spring容器的關鍵概念和特性。

資源:
瞭解了Spring IoC容器之後,瞭解“第四章,資源”所介紹的關於Spring的資源抽象(resources abstract)概念是什麼必要的。提供給ApplicationContext構造器的位置路徑實際上是資源串,它用來告訴容器從外部資源加載配置元數據,如本地的文件系統或者是JavaClasspath等。
 請記住,在大多數的應用情況下,Spring IoC容器是不需要用戶代碼來實例化的。例如,在典型的J2EE應用中,大約只需要8行左右的XML配置信息即可(web.xml)。
 在最基本的情況下,Spring IoC容器配置信息需要包含至少一個bean的定義,實際上大多數情況下都超過一個。當使用XML配置方式時,關於bean的配置內容包含在<bean/>和<beans>元素內。
 對應於實際對象的這些bean應用組織起你的應用。一般情況下,你需要定義的bean包括服務層對象,數據訪問對象(DAOs),表現層對象(例如Structs Action實例),基礎底層對象(Hibernate SessionFactory實例),JMS序列(Queue)引用等。(當然,還有很多其他的可能需要配置的信息,這取決於你的應用複雜度)。
 下面就是一個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>
3.2.2初始化容器
 初始化Spring容器十分方便;參看下面的例子。
例1:
Resource resource = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
例2:
 
ClassPathResource resource = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
例3:
ApplicationContext context = new ClassPathXmlApplicationContext(
        new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
// of course, an ApplicationContext is just a BeanFactory
BeanFactory factory = (BeanFactory) context;
3.2.2.1 組織XML配置文件
 將容器配置文件分解成多個XML配置文件是什麼有用的。加載多個XML文件的方法之一是利用應用上下文(application context)的構造器來讀取多個資源(Resource)位置。利用bean factory,一個bean的定義讀取器(reader)可以在讀取每個配置文件的時候重複使用。
 一般來說,Spring團隊推薦上面的方法,因爲這種方法使得配置文件的讀取對於容器是透明的。另外一個替代的方法是在定義文件中使用<import>元素來定義其他的bean定義文件。<import/>元素必須放置在<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>
本例中,外部的bean定義從services.xmlmessageSource.xmlthemeSource.xml三個文件中加載。所有的位置路徑是相對於定義文件的,因此services.xml和定義文件必須在相同的路徑,而messageSource.xmlthemeSource.xml是在相對路徑的resources目錄下面。可以看出,路徑開頭的/已經被省略,這些路徑被認爲是相對路徑,或許這是種更好的方式。
 導入的配置文件內容必須符合包含在定義文件頭部的Schema或者DTD的合法性驗證。
3.2.3 Beans
 正如前面所述,Spring IoC容器管理一個或者多個Bean。容器按照定義的配置元數據(典型的爲XML的bean定義文件)來創建bean。
 在容器內部,這些bean的定義被表示成BeanDefinition對象,其中包含以下的元數據:
l         一個類名(包含包定義):這實際上是這個bean的實現類。然而,如果這個bean是通過調用靜態的工廠方法創建的(而不是通過正常的構造器創建的),這個實際上是這個工廠類的名字。
l         Bean的行爲配置元素,用來告訴容器bean在容器中的行爲(如原型、單例、自裝配模式、依賴檢查模式以及初始化(initialization)和消除(destruction)方法)。
l         新創建的bean的構造器參數和屬性值。例如bean中用來管理的連接池數量(可以作爲屬性指定,也可以作爲構造器參數),或者連接池大小。
l         Bean正常運行所需要的其他的bean說明,例如合作者(或者叫依賴)。
上面提到的概念在定義文件中對應於bean定義的屬性集合。下面給出了一些屬性的詳細文檔鏈接。
 3.1. bean定義
Feature
Explained in...
class
name
scope
constructor arguments
properties
autowiring mode
dependency checking mode
lazy-initialization mode
initialization method
destruction method
 除了通過bean定義文件來創建bean以外,某些BeanFactory實現也允許註冊那些已經在工廠之外創建的對象(通過用戶代碼創建)。DefaultListableBeanFactory類就支持registerSingleton(..)方法。然而,典型的應用一般還是通過bean定義的方式來實現bean的創建和管理。
3.2.3.1 命名Beans

Bean的命名規範:
Bean的命名規範(至少在Spring開發團隊中是這樣)是使用標準的Java命名規範。具體規範如下,bean的名字以小寫字母開頭,並且是camel-cased。例如:'accountManager', 'accountService', 'userDao', 'loginController'等等。按照統一的方式來命名bean,將會使得你的配置內容更易於閱讀和理解;採用這樣的命名規範並不困難,採用Spring AOP框架的時候,它可以在bean的命名方面給與很多提示和建議。
每個bean都有一個或者多個標識(也叫標識符,或者名字;這些指的都是同樣的東西)。這些標識符在容器中必須是唯一的。通常bean只有一個標識,但當bean有超過一個標識時,其他的標識可以看作是別名。
使用XML配置文件時,使用'id'或者'name'來指定bean的標識。'id'屬性允許你指定一個beanID,由於這是XML元素的ID屬性,XML解析器能夠在別的元素引用這個ID的時候做完全的驗證。然而,XML規範限制了XML ID中使用的字符類型。通常這不會造成影響,但如果你需要使用特定的XML字符,或者爲bean取別名的時候,你可以在'name'屬性中指定多個標識,標識之間以逗號(,),分號(;)或者空格分隔。
注意,你並不一定要爲bean命名。如果沒有命名,容器將會爲bean創建一個唯一的名字。不命名bean的目的將會在後面討論(一種情況是內部bean-inner beans)。
3.2.3.1.1 Bean別名
bean定義中,你可以通過ID屬性指定bean的名字,然後再通過alias屬性來指定bean的別名。所有的名字指向同一個bean,這在有些情況下很有用,允許應用的組件使用與組件名字有關的bean別名來引用bean
然後,在bean定義的時候,就必須要指定所有的別名似乎不太合適。有的時候爲在其他地方定義的bean來定義一個別名是什麼必要的。在XML配置方式中,可以通過獨立(standalone)的<alias/>元素來實現這點。例如:
<alias name="fromName" alias="toName"/>
上面的例子中,在同一容器的bean叫做'fromName',在使用上面的別名定義之後,可以用'toName'來引用這個bean
舉個具體的例子,例如組件A在它的XML配置中定義了一個DataSource bean叫做componentA-dataSource。組件B希望在它的配置中用componentB-dataSource來引用這個bean。同時,主應用MyApp則定義了自己的XML配置,並且裝配了來自三個不同XML配置的應用上下文,要用myApp-dataSource來引用bean。對於這種情況可以在用下面的配置方式很方便的實現:
<alias name="componentA-dataSource"
 alias="componentB-dataSource"/>
<alias name="componentA-dataSource" alias="myApp-dataSource" />
現在每個組件,包括主應用都以一個不會和其他定義發生衝突的名字來應用這個dataSource了。
3.2.3.2 初始化bean
Spring IoC容器中,bean的定義配置是創建一個或者多個實際對象的依據。容器參照bean定義並且使用配置數據來定義和創建一個實際的對象。本章關注的是對於作爲開發者的你來說,怎樣去告知Spring IoC容器要初始化的對象類型是什麼,怎樣去初始化對象。
如果你使用XML配置方式,你可以用’class’屬性來指定對象的類型。’class’屬性(在容器的BeanDefinition實例中表示爲Class屬性)是必須的(參照第3.2.3.2.2-“使用實例工廠方法來初始化”和第3.6-Bean定義繼承”),並且有兩個目的。大多數情況下,Class屬性告知容器去哪兒以反射方式調用構造器來創建bean實例(類似於java’new’方法)。
在調用靜態工廠方法創建bean的情況下,class屬性指定的是包含靜態工廠方法的類(返回的對象類型可能是同一個類,也可能是另外的類,這無關緊要)。
3.2.3.2.1 使用constructor實例化bean
當使用構造器來創建bean的時候,Spring支持對於大多數的常規的類的創建。也就是說,這些類不需要實現特定的接口,或者要求以特定的方式來編碼。只要指定bean的類就可以。然後,依賴於IoC容器的類型,你可能需要一個默認(空的)構造器。
Spring IoC容器除了管理JavaBean以外,也可以虛擬地管理你要管理的任何類。大多數使用Spring的人更細化將真正的JavaBean(有默認的(無參數)構造器,並且有合適的settergetter方法)放到容器中,當然,也可以將“非bean類型”(non-bean-style)的類放在容器中。例如,當你要使用一個完全不符合JavaBean規範的連接池對象的時候,Spring同樣可以很好的管理。
XML配置中,可以用如下的方式來定義bean
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
如何指定構造器參數(如果需要的話),或者如何設置對象實例的屬性,這些將稍後描述。
3.2.3.2.2 使用靜態工廠方法(static factory method)實例化bean
當使用靜態工廠方法來定義bean時,class屬性指定包含靜態工廠方法的類,factory-method屬性用來指定工廠方法名。Spring調用工廠方法(調用可選的參數列表,後面介紹)然後返回一個活動的對象,在外面看來和利用構造器方法創建bean實例一樣。這種創建方法的一個用處是在代碼中調用靜態工廠方法。
下面的例子說明了通過工廠方法來創建bean的定義文件。注意下面的定義並沒有指定返回對象的類型,只指定了工廠方法。例子中的createInstance()方法必須是一個靜態方法。
<bean id="exampleBean"
      class="examples.ExampleBean2"
      factory-method="createInstance"/>
靜態工廠方法的參數(可選)制定方法和對象實例的屬性設置方法(setter)將在後面說明。
3.2.3.2.3 使用實例工廠方法(instance factory method)實例化bean
有點類似於靜態工廠方法,實例工廠方法是通過調用容器中存在的bean實例的工廠方法來創建新的bean
要用這個方法創建bean’class’屬性必須爲空,而’factory-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)的方式來配置它。
3.2.4使用容器
BeanFactory只不過是一個能夠維護不同的bean以及它們之間關係的註冊的高級工廠的接口。BeanFactory使得你可以讀取bean定義文件並且訪問它們。當只使用BeanFactory的時候,你需要創建一個BeanFactory,並且讀取BeanXML定義文件。例如:
InputStream is = new FileInputStream("beans.xml");
BeanFactory factory = new XmlBeanFactory(is);
上面基本就是創建容器要做的一切。利用getBean(String)方法,你可以檢索bean的實例;BeanFactory的客戶端接口相當簡單,僅僅有六個供客戶代碼調用的接口:
l        boolean containsBean(String):如果BeanFactory包含匹配參數的bean定義或者bean實例,則返回true
l        Object getBean(String):按照指定的參數返回bean實例。依據當前beanBeanFactory中配置的不同,可能返回單例(共享實例),或者是一個新創建的bean實例。如果bean不存在,或者正在被初始化,那麼方法將返回一個BeansException異常(前者將會返回NoSuchBeanDefinitionException異常)。
l        Object getBean(String, Class):然會一個指定參數的bean實例,同時將返回的bean強制轉換爲指定的Class類型。如果當前bean不能被轉換,那麼將拋出BeanNotOfRequiredTypeException異常。此外,所有getBeans(String)的規範也同樣適用本方法。
l        Class getType(String name):返回指定名稱的beanClass類型。同樣,如果沒有找到bean,拋出NoSuchBeanDefinitionException異常。
l        boolean isSingleton(String):判斷當前bean是否是單例(後面將解釋單例)。如果沒有找到bean,拋出NoSuchBeanDefinitionException異常。
l        String[] getAliases(String):返回在bean定義文件中定義的別名數組。
發佈了28 篇原創文章 · 獲贊 6 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章