Spring 核心技術(2)

1.3 Bean概述html

Spring IoC 容器管理一個或多個bean,他們都是根據提供的配置元數據(例如 XML 中<bean/>定義)建立的。java

在容器內部,這些 bean 定義以 BeanDefinition 對象進行表示,其中包含(以及其餘信息)如下元數據:spring

  • 包限定的類名:一般是 bean 的實際實現類
  • Bean 行爲配置元素,定義 bean 在容器中的行爲方式(範圍,生命週期回調等)
  • 引用 bean 執行工做所需的其餘 bean,這些引用也稱爲協做者或依賴項
  • 要在新建立的對象中設置的其餘配置。例如鏈接池中鏈接池的大小和鏈接數。

元數據能夠轉換爲構成每一個 bean 定義的一組屬性。下表描述了這些屬性:api

屬性轉換目標
類(Class)實例化 Bean
名稱(Name)Bean 名稱
範圍(Scope)Bean 做用範圍
構造函數參數(Constructor arguments)依賴注入
屬性(Properties)依賴注入
自動裝配模式(Autowiring mode)自動裝配協做者
延遲初始化模式(Lazy initialization mode)延遲初始化 Bean
初始化方法(Initialization method)初始化回調
銷燬方法(Destruction method)銷燬回調併發

除了包含如何建立特定 bean 的 bean 定義以外,ApplicationContext 實現類還容許用戶已經在容器外建立的對象進行註冊。這些任務經過使用 getBeanFactory() 方法訪問應用程序上下文的 Bean 工廠來完成,該方法返回 Bean 工廠的實現類 DefaultListableBeanFactory。DefaultListableBeanFactory 經過 registerSingleton(..) 和 registerBeanDefinition(..) 方法支持此註冊過程。然而通常狀況下應用程序僅使用經過常規 bean 定義元數據定義的 bean。函數

Bean 元數據和手動提供的單例實例須要儘量早的註冊,以便容器在自動裝配和其餘內省步驟期間正確的推理。雖然在某種程度上支持覆蓋現有元數據和現有單例實例,可是在運行時(與對工廠的實時訪問同時)註冊新 bean 並未獲得官方支持,而且可能致使併發訪問異常或 bean 容器中的狀態不一致。

1.3.1 Bean 命名ui

每一個bean都有一個或多個標識符。這些標識符在託管 bean 的容器中必須是惟一的。一個 bean 一般只有一個標識符。若是它須要多個,則額外的能夠被視爲別名。this

在基於 XML 的配置元數據中,您可使用 id 屬性、name 屬性或者二者都用來指定 bean 標識符。id 屬性容許您指定一個準確的 id。通常來講這些名稱包含字母和數字('myBean','someService'等),但它們也能夠包含特殊字符。若是你想要爲 bean 引入其餘別名,還能夠在 name 屬性中指定它們,使用逗號(,)、分號(;)或空格進行分隔。做爲歷史記錄,在 Spring 3.1 以前的版本中,id 屬性被定義爲一種 xsd:ID 類型,它限制了可用的字符。從 3.1 開始,它被定義爲一種 xsd:string 類型。請注意,bean id 在容器內必須惟一,但 XML 解析器不會進行限制。編碼

bean 的 name 和 id 並非必填的。若是你沒有顯式提供 name 或 id,則容器會爲該 bean 生成惟一的名稱。可是若是須要經過使用 ref 元素或Service Locator樣式按名稱引用該 bean 則必須提供名稱。在使用內部 Bean 或自動裝配協做者時能夠不提供名稱。htm

Bean命名約定

在命名 bean 時約定使用 Java 實例字段命名規範。也就是說,bean 名稱以小寫字母開頭並遵循駝峯法。這樣的名字的例子包括 accountManager、accountService、userDao、loginController等等。
命名 bean 始終使你的配置更易於閱讀和理解。此外,若是使用 Spring AOP,那麼在將切面織入使用 name 進行關聯的一組 bean 時,它會有很大幫助。

經過類路徑中的組件掃描,Spring 按照前面描述的規則爲未命名的組件生成 bean 名稱:實質上是簡單的使用類名並將其初始字符轉換爲小寫。可是,在特殊狀況下,當類名中有多個字符且第一個和第二個字符都是大寫字母時,原始格式將被保留。Spring 遵循 java.beans.Introspector.decapitalize 定義的規則。

在 Bean 定義以外爲其建立別名

在 bean 定義自己中,能夠組合使用單個 id shuxing 和任意數量的 name 屬性爲 bean 提供多個名稱。這些名稱能夠是同一個 bean 的等效別名,在某些狀況下頗有用,例如讓應用程序中的每一個組件經過使用特定於該組件自己的 bean 名稱來引用公共依賴項。

可是,只在 Bean 定義時指定別名是不夠的,有時須要爲其餘地方定義的 bean 引入別名。在大型系統中,每一個子系統之間的配置一般是分離的,每一個子系統都有本身的一組對象定義。在基於 XML 的配置元數據中,您可使用<alias/>元素來完成此任務。如下示例顯示瞭如何執行此操做:

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

在示例中,同一容器中名稱爲 fromName 的 Bean 在使用這種別名定義以後也能夠叫作 toName。

例如,子系統 A 的配置元數據經過名稱 subsystemA-dataSource 引用數據源。子系統 B 的配置元數據經過名稱 subsystemB-dataSource 引用數據源。在編寫同時使用這兩個子系統的主應用程序時,主應用程序經過名稱 myApp-dataSource 引用數據源。要使這三個名稱引用同一對象,能夠將如下別名定義添加到配置元數據中:

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

如今,每一個組件和主應用程序均可以經過一個惟一的名稱引用 dataSource,並保證不與任何其餘定義衝突(實際上建立了一個命名空間),但它們引用相同的 bean。

基於 Java 的配置

若是使用 Javaconfiguration,則 @Bean 註解能夠提供別名。有關詳細信息,請參閱使用 @Bean 註解

1.3.2 初始化 Bean

bean 定義本質上是建立一個或多個對象的方法。容器在被請求時查找已經命名的 bean 的方法,並使用由該 bean 定義封裝的配置元數據來建立(或獲取)實際對象。

若是使用基於 XML 的配置元數據,則須要在 <bean/> 元素的 class 屬性指定對象類型。此 class 屬性一般是必需的(對應 BeanDefinition 實例的 Class 屬性)。(有關例外的狀況,請參閱使用實例工廠方法進行實例化Bean定義繼承)。你能夠經過如下兩種方式之一使用 Class 屬性:

  • 容器經過反射調用 Bean 的構造函數(相似於使用 new 運算符的 Java 代碼)直接建立 Bean 的狀況下指定要構造的 bean 類型。
  • 調用指定包含靜態工廠方法的實際類來建立對象,在不太常見的狀況下,容器調用類中的靜態工廠方法來建立 bean。經過調用靜態工廠方法返回的對象類型能夠徹底是同一個類或另外一個類。
內部類名
若是要爲靜態嵌套類配置 bean 定義則必須使用嵌套類的二進制名稱。

例如,若是在 com.example 包中有一個類叫作 SomeThing,而且 SomeThing 類有一個靜態嵌套類叫作 OtherThing,則 bean 定義中的 class屬性值將爲 com.example.SomeThing$OtherThing。

請注意,類名中 $ 字符用於將嵌套類名與外部類名分開。

使用構造函數實例化

當您經過構造方法建立 bean 時,全部普通類均可以使用並與 Spring 兼容。也就是說,須要開發的類不須要實現任何特定接口或以某種特定方式進行編碼。簡單地指定 bean 的類就足夠了。取決於指定 bean 使用的 IoC 類型,有時候你可能須要一個默認構造函數。

Spring IoC 容器幾乎能夠管理你但願它管理的任何類。它不只限於管理真正的 JavaBean。大多數 Spring 用戶更傾向於使用只有一個默認構造函數且在屬性以後由合適的 setter 和 getter 的 JavaBean。你還能夠在容器中包含一些外部的非 bean 樣式類。例如,若是須要使用徹底不符合 JavaBean 規範的傳統鏈接池,Spring 也能夠對其進行管理。

使用基於 XML 的配置元數據,你能夠按以下方式指定 bean 類:

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

有關爲構造函數提供參數的機制(若是須要)以及在構造對象後設置對象實例屬性的詳細信息,請參閱注入依賴項

使用靜態工廠方法實例化

定義使用靜態工廠方法建立的 bean 時,請使用 class 屬性指定包含靜態工廠方法的類,並使用 factory-method 屬性指定工廠方法自己的名稱。你應該可以調用此方法(如後面示例所述,使用可選參數)並返回一個活動對象,隨後將其視爲經過構造函數建立的對象。這種 bean 定義的一個用途是在傳統代碼中調用靜態工廠。

如下 bean 定義演示經過調用工廠方法來建立 bean。該定義未指定返回對象的類型(類),僅指定了包含工廠方法的類。在此示例中,createInstance()方法必須是靜態方法。如下示例顯示如何指定工廠方法:

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

如下示例顯示了一個可使用以前 bean 定義的類:

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

有關爲工廠方法提供(可選)參數以及從工廠類返回對象後設置對象實例屬性的機制的詳細信息,請參閱依賴關係和詳細配置

使用實例工廠方法實例化

與經過靜態工廠方法實例化相似,使用實例工廠方法進行實例化會調用容器現有 bean 的非靜態方法來建立新 bean。要使用此機制,請將 class 屬性保留爲空,並在 factory-bean 屬性中指定當前(或父或祖先)容器中包含調用後建立對象的實例化方法的 bean 的名稱。使用 factory-method 屬性設置工廠方法自己的名稱。如下示例顯示如何配置此類 bean:

<!-- the factory bean, which contains a method called 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"/>

如下示例展現了相應的Java類:

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

一個工廠類也能夠包含多個工廠方法,如如下示例所示:

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

如下示例展現了相應的Java類:

public class DefaultServiceLocator {    private static ClientService clientService = new ClientServiceImpl();    private static AccountService accountService = new AccountServiceImpl();    public ClientService createClientServiceInstance() {        return clientService;    }    public AccountService createAccountServiceInstance() {        return accountService;    }}

這種方法代表工廠 bean 自己能夠經過依賴注入(DI)進行管理和配置。

相關文章
相關標籤/搜索