Spring IoC容器管理一個或多個bean,這些bean是使用你提供給容器的配置元數據建立的(例如,以XML <bean/>
定義的形式)。java
在容器內部,這些bean定義被表示爲BeanDefinition
對象,其中包含(其餘信息)如下元數據:spring
此元數據轉換爲組成每一個bean定義的一組屬性,下表描述了這些屬性:segmentfault
屬性 | 解釋 |
---|---|
Class | 實例化Bean |
Name | 命名Bean |
Scope | Bean做用域 |
構造函數參數 | 依賴注入 |
屬性 | 依賴注入 |
自動裝配模式 | 自動裝配協做者 |
延遲初始化模式 | 延遲初始化Bean |
初始化方法 | 初始化回調 |
銷燬方法 | 銷燬回調 |
除了包含關於如何建立特定bean的信息的bean定義以外,ApplicationContext
實現還容許註冊(由用戶)在容器外部建立的現有對象,經過getBeanFactory()
方法訪問ApplicationContext
的BeanFactory
,該方法返回BeanFactory DefaultListableBeanFactory
實現。DefaultListableBeanFactory
經過registerSingleton(..)
和registerBeanDefinition(..)
方法支持這種註冊,然而,典型的應用程序只使用經過常規bean定義元數據定義的bean。api
Bean元數據和手動提供的單例實例須要儘早註冊,以便容器在自動裝配和其餘內省步驟中正確地推斷它們,雖然在某種程度上支持覆蓋現有的元數據和現有的單例實例,可是在運行時註冊新bean(與對工廠的實時訪問同時進行)並非官方支持的,而且可能會致使併發訪問異常、bean容器中不一致的狀態,或者二者兼有。
每一個bean都有一個或多個標識符,這些標識符在承載bean的容器中必須是唯一的,bean一般只有一個標識符,可是,若是須要多個,則能夠將額外的標識符視爲別名。併發
在基於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生成惟一的名稱,可是,若是你但願經過名稱引用該bean,經過使用ref
元素或服務定位器樣式查找,你必須提供一個名稱,不提供名稱的動機與使用內部bean和自動裝配協做者有關。ui
Bean命名約定
約定是在爲bean命名時使用標準Java約定做爲實例字段名,也就是說,bean名稱以小寫字母開頭,並採用駝峯大小寫,此類名稱的示例包括
accountManager
、accountService
、userDao
、loginController
等等。this一致地命名bean使你的配置更容易閱讀和理解,另外,若是你使用Spring AOP,當你將advice應用到一組按名稱關聯的bean時,它會提供很大的幫助。編碼
使用類路徑中的組件掃描,Spring按照前面描述的規則爲未命名的組件生成bean名稱:本質上,取簡單的類名並將其初始字符轉換爲小寫,可是,在(不尋常的)特殊狀況下,若是有多個字符,而且第一個和第二個字符都是大寫的,則保留原來的大小寫,這些規則與
java.beans.Introspector.decapitalize
(Spring在這裏使用)定義的規則相同。
在bean定義自己中,可使用id
屬性指定的最多一個名稱和name
屬性中任意數量的其餘名稱的組合,爲bean提供多個名稱。這些名稱能夠是相同bean的等價別名,在某些狀況下很是有用,好比經過使用特定於該組件自己的bean名稱,讓應用程序中的每一個組件引用公共依賴項。code
可是,指定實際定義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"/>
如今,每一個組件和主應用程序均可以經過唯一的名稱引用數據源,而且保證不會與任何其餘定義衝突(有效地建立名稱空間),可是它們引用的是同一個bean。
Java配置
若是使用Java配置,可使用
@Bean
註解提供別名,有關詳細信息,請參見使用@Bean
註解。
bean定義本質上是建立一個或多個對象的配方,當被詢問時,容器會查看命名bean的配方,並使用該bean定義封裝的配置元數據來建立(或獲取)一個實際對象。
若是使用基於XML的配置元數據,則要在<bean/>
元素的class
屬性中指定實例化的對象的類型(或類),這個class
屬性(在內部是BeanDefinition
實例上的一個Class
屬性)一般是強制性的,你能夠經過如下兩種方式之一使用Class
屬性:
new
操做符的Java代碼。static
工廠方法的實際類,在不太常見的狀況下,容器調用類上的static
工廠方法來建立bean,從static
工廠方法調用返回的對象類型能夠是同一個類,也能夠徹底是另外一個類。內部類的名字若是要爲
static
嵌套類配置bean定義,必須使用嵌套類的二進制名稱。例如,若是你在
com.example
包中有一個名爲SomeThing
類,這個類有一個static
嵌套類叫作OtherThing
,bean定義上的class
屬性的值是com.example.SomeThing$OtherThing
。注意,在名稱中使用
$
字符將嵌套的類名與外部類名分隔開。
當你使用構造函數方法建立bean時,全部的普通類均可以被Spring使用並與Spring兼容,也就是說,正在開發的類不須要實現任何特定的接口或以特定的方式編碼,只需指定bean類就足夠了。可是,根據你爲特定bean使用的IoC類型,你可能須要一個默認(空)構造函數。
Spring IoC容器幾乎能夠管理你但願它管理的任何類,它不只限於管理真正的JavaBean,大多數Spring用戶更喜歡實際的JavaBean,它只有一個默認(無參數)構造函數,以及根據容器中的屬性建模的適當的setter
和getter
。你還能夠在容器中包含更多非bean樣式的類,例如,若是你須要使用徹底不符合JavaBean規範的遺留鏈接池,Spring也能夠很好的管理它。
使用基於XML的配置元數據,你能夠指定你的bean類以下:
<bean id="exampleBean" class="examples.ExampleBean"/> <bean name="anotherExample" class="examples.ExampleBeanTwo"/>
有關向構造函數提供參數(若是須要)和在構造對象以後設置對象實例屬性的機制的詳細信息,請參閱注入依賴項。
在定義使用靜態工廠方法建立的bean時,使用class
屬性指定包含static
工廠方法的類,使用factory-method
屬性指定工廠方法自己的名稱。你應該可以調用這個方法(帶有可選參數,如後面所述)並返回一個活動對象,隨後將其視爲經過構造函數建立的,這種bean定義的一個用途是在遺留代碼中調用static
工廠。
下面的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)進行管理和配置。
在Spring文檔中,「工廠bean」指的是在Spring容器中配置的bean,它經過實例或靜態工廠方法建立對象,相反,FactoryBean
(注意大小寫)指的是特定於spring的FactoryBean
。