IoC容器3——Bean總覽

一個Spring IoC容器管理者一個或多個bean。這些 bean 由提供給容器的配置元數據建立,例如以 XML <bean/> 的形式。java

在容器自身的內部,這些bean的定義被表示成BeanDefinition對象,其中包含如下元數據:api

  • 限定包類名:典型的是bean定義的實際實現類;
  • Bean行爲配置元素,決定bean在容器中的衛星(範圍、生命週期回掉等等);
  • bean必須的指向其它ben的引用,這些引用也被稱爲協做或依賴;
  • 新建立對象時的其它配置,例如管理鏈接池的bean的鏈接數,或者鏈接池的大小。

元數據被翻譯爲組成每一個bean定義的一組屬性:併發

class, name, scope, contructor arguments, properties, autowiring mode, lazy-initalization mode, initialization method, destruction method.函數

bean定義包含了如何建立特定bean的信息,做爲它的補充,ApplicationContext的實現也容許用戶註冊容器意外建立、已存在的bean。這須要經過getBeanFactory()方法獲取ApplicationContext的BeanFactory,這個方法返回BeanFactory的實現了DefaultListableBeanFactory。DefaultListableBeanFactory支持經過registerSingleton(...)方法和registerBeanDefinition(...)方法註冊bean。然而,典型的應用程序應該惟一的經過元數據註冊bean。ui

須要儘早註冊 Bean 元數據和手動提供的單例實例,這是爲了使容器在自動裝配和其餘內省步驟能正確的識別它們。雖然在某種程度上可以支持覆蓋現有的元數據和現有的單例實例,可是在運行時註冊新的bean(併發的實時訪問factory)不被官方支持,這可能會產生併發訪問異常和(或)bean容器狀態不一致。this

1 命名bean

每一個bean都有一個或多個標識。這些表示必須在持有它的容器中惟一。通常一個bean只有一個標識,可是若是須要多個,額外的標識能夠考慮使用別名。編碼

在XML格式的配置元數據中,可使用id和(或)name屬性做爲bean的標識。只容許指定一個id。按照慣例,name能夠是字母和數字(myBean,fooService等等),可是也能夠包含特殊字符。若是想給bean引入其它別名,能夠在name屬性中聲明它們,用逗號、分號或者空格分隔。在Spring 3.1以前的版本中,id屬性被定義爲一個xsd:ID類型,它限制了可能的字符。從3.1開始,它被定義爲xsd:string類型。須要注意的是bean id的惟一性由容器執行,再也不由XML解析器保證。spa

不要求必須爲bean提供一個名字或id。若是沒有提供名字和id,容器爲bean生成一個惟一的名字。可是,若是想使用名字來引用一個bean(經過使用ref元素或Service Locator方式查找),就必須提供一個名字。不提供名字屬性是由於使用內部bean和自動裝配協做者。翻譯

bean 命名約定

命名bean的約定使用實例化域(field)名字的標準Java約定。即bean的名字以小寫字母開頭,後面採用駝峯式。例如accountManager、accountService、userDao、loginController等等。code

bean命名的一致性,使得你的配置易於閱讀和理解;而且在使用Spring AOP時,向一組名字相關的bean應用advise時,會有很大的幫助。

在classpath進行組件搜索時,Spring給未命名的組件生成名字,遵循如下規則:使用簡單的類名,並將它的首字母小寫。可是在特殊狀況下類名不只僅是首字母而是前兩個字母都大寫,此時默認的規則將不會生效。而是使用java.beans.Introspector.decapitalize定義的規則。

在bean定義以外指定bean的別名

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

在bean實際定義的地方具體說明全部別名是不恰當的。有時須要在其它地方爲bean引入一個別名。這種狀況在一個被分爲許多子系統的大型系統中十分常見,每一個子系統有本身的一組對象定義。在XML格式的配置元數據中,可使用<alias/>元素完成這項任務。

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

在上例中,在同一容器中的bean被命名爲fromName,在使用了這個別名定義後,可使用toName引用它。

例如,A子系統的配置元數據也許使用名稱subsystemA-dataSource引用一個DataSource。B子系統的配置元數據使用名字subsystemB-dataSource引用一個DataSource。當將這些子系統與主應用組合到一塊兒時,主應用使用myApp-dataSource引用DataSource。爲使這三個名字指向同一對象,能夠在MyApp的配置元數據中加入如下定義:

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

這樣每一個組件和主應用均可以經過惟一的名字引用dataSource,並保證不會與任何其餘定義(有效建立的命名空間)衝突,可是它們都引用同一個bean。

Java配置

若是使用Java配置,@Bean註解能夠用來提供別名。

2 實例化bean

bean定義其實就是建立一個或多個對象的規則。在查詢時容器會查看命名bean的規則,並使用由該bean定義封裝的配置元數據建立(或獲取)實際對象。

若是使用XML格式的配置元數據,能夠經過bean元素的class屬性指定將要實例化的對象的類型(class)。 在BeanDefinition實例內部,這個class元素屬性是一個Class類型的域(field/property),這個元素屬性是必需的。可經過如下兩種方式之一使用Class屬性:

  • 一般狀況下,直接經過反射調用構造方法來建立 bean,和在 Java 代碼中使用 new 有點相似;
  • 指定一個實際的類,它包含將被調用以建立對象的靜態工廠方法;在少數狀況下,容器調用類的靜態工廠方法建立bean。調用靜態工廠方法返回的對象類型多是同一個類,也可能徹底是另外一個類。

內部類的名稱

若是想配置一個靜態內部類的bean定義,必須使用內部類的二進制名稱。例如,在com.example包中有一個名爲Foo的類,而且這個類有一個靜態內部類名爲Bar,那麼這個bean定義的class屬性應該爲com.example.Foo$Bar。注意在名字中使用$分隔外部類和內部類。

使用構造函數實例化

當經過構造函數的方法建立一個bean時,全部正常類均可以使用,並與Spring兼容。即正在開發的類不須要實現任何特定的接口或以特定方式編碼。只需指定bean類便可。可是根據特定bean使用的IoC類型,可能須要一個默認(空)構造函數。

Spring IoC容器幾乎能夠管理您想要管理的任何類;不限於管理真正的JavaBeans。大多數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時,您可使用class屬性指定包含靜態工廠方法的類和factory-method的屬性,以指定工廠方法自己的名稱。您應該能夠調用此方法(可使用可選的參數),並返回一個活動對象,這個對象隨後將會與經過構造函數建立的對象同樣對待。這種bean定義的一個用途是調用舊代碼中的靜態工廠。

下面的bean定義指定一個經過調用工廠方法建立的bean。定義不須要指定返回對抗的類型,只須要指定包含工廠方法的類。在下面的例子中createInstance()方法必須是靜態方法。

<bean id="clientService"
    class="examples.ClientService"
    factory-method="createInstance"/>
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屬性中指定工廠方法的名字。

<!-- 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"/>
public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();
    private DefaultServiceLocator() {}

    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"/>
public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();
    private static AccountService accountService = new AccountServiceImpl();

    private DefaultServiceLocator() {}

    public ClientService createClientServiceInstance() {
        return clientService;
    }

    public AccountService createAccountServiceInstance() {
        return accountService;
    }
}

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

在Spring文檔中,factory bean是指在Spring容器中配置的工廠類經過實例或靜態工廠方法來建立對象的bean。而 FactoryBean (注意大小寫) 表明了Spring中特定的 FactoryBean。

相關文章
相關標籤/搜索