一塊兒來讀官方文檔-----SpringIOC(02)

1.3。Bean總覽

Spring IoC容器管理一個或多個bean。這些bean是使用您提供給容器的配置元數據建立的(例如,以XML <bean/>定義的形式 )。java

在容器自己內,這些bean定義表示爲BeanDefinition對象,其中包含(除其餘信息外)如下元數據:spring

包限定的類名:一般,定義了Bean的實際實現類。
Bean行爲配置元素,用於聲明Bean在容器中的行爲(做用域,生命週期回調等)。
引用其餘bean進行其工做所需的bean。這些引用也稱爲協做者或依賴項。
要在新建立的對象中設置的其餘配置設置-例如,池的大小限制或在管理鏈接池的Bean中使用的鏈接數。 api

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

屬性 解釋
實例化bean
名稱 bean名稱
生命週期 bean生命週期
構造函數參數 依賴注入
屬性 依賴注入
自動注入模式 自動注入的合做者
延遲初始化模式 懶初始化bean
初始化方法 初始化回調
銷燬方式 銷燬回調

除了包含有關如何建立特定bean的信息的bean定義外,這些ApplicationContext實現還容許註冊在容器外部(由用戶)建立的現有對象。這是經過方法訪問ApplicationContext的BeanFactory的getBeanFactory()來完成,該方法返回BeanFactory的DefaultListableBeanFactory實現。DefaultListableBeanFactory 經過registerSingleton(..)和 registerBeanDefinition(..)方法支持此註冊。可是,典型的應用程序僅使用經過常規bean定義元數據定義的bean。函數

自定義類  不帶任何註解
    public class LearnBean {
        public LearnBean(String name) {
        }
        public String getString(){
            return "learnSpring";
        }
    }
    
第一種:AnnotationConfigApplicationContext自帶的registerBean方法,能夠傳入class和構造參數

    AnnotationConfigApplicationContext annotationConfigApplicationContext = 
                                new AnnotationConfigApplicationContext();
    annotationConfigApplicationContext.registerBean(LearnBean.class,"");
    annotationConfigApplicationContext.refresh();
    LearnBean bean = (LearnBean) annotationConfigApplicationContext.getBean("learnBean");
    System.out.println(bean.getString());
    
第二種:還能夠傳入 class和beanDefinition也就是配置元數據 這個和 getBeanFactory().registerBeanDefinition(..)是一個意思

    AnnotationConfigApplicationContext annotationConfigApplicationContext = 
                                new AnnotationConfigApplicationContext();
    
    RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(LearnBean.class);
    ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
    constructorArgumentValues.addIndexedArgumentValue(0,"111");
    rootBeanDefinition.setConstructorArgumentValues(constructorArgumentValues);
    annotationConfigApplicationContext.registerBeanDefinition("learnBean",rootBeanDefinition);

    annotationConfigApplicationContext.refresh();

    LearnBean bean = (LearnBean) annotationConfigApplicationContext.getBean("learnBean");
    System.out.println(bean.getString());
    
    
注意:若是不寫
    annotationConfigApplicationContext.refresh();
就會報錯
Exception in thread "main" java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@68de145 has not been refreshed yet
    at org.springframework.context.support.AbstractApplicationContext.assertBeanFactoryActive(AbstractApplicationContext.java:1096)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1108)
    at org.springframework.example.DebuggerSpringMain.main(DebuggerSpringMain.java:40)

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

很顯然註冊太晚,就沒法和Spring基礎的步驟融合,一些依賴注入沒法完成
1.3.1。bean的命名

每一個bean具備一個或多個標識符。這些標識符在承載Bean的容器內必須惟一。
一個bean一般只有一個標識符。可是,若是須要多個,則能夠將多餘的別名視爲別名。this

在基於XML配置文件,您可使用id屬性,name屬性,或二者來指定bean標識符。id屬性使您能夠精確指定一個ID。
按照慣例,這些名稱是字母數字(「myBean」,「someService」等),但它們也能夠包含特殊字符。若是要爲bean引入其餘別名,還能夠在name屬性中指定它們,並用逗號(,),分號(;)或空格分隔。
做爲歷史記錄,在Spring3.1以前的版本中,該id屬性被定義爲一種xsd:ID類型,該類型限制了可能的字符。從3.1開始,它被定義爲xsd:string類型。
請注意,Bean id惟一性仍由容器強制執行,儘管再也不由XML解析器執行。編碼

您不須要爲bean 提供name或id。若是不提供 name或id顯式提供,則容器將爲該bean生成一個惟一的名稱。
可是,若是您但願經過使用ref元素或服務定位器樣式查找經過名稱引用那個bean,那麼您必須提供一個名稱。使用內部bean 和 自動裝配合的時候 一般不須要使用名稱。代理

###### Bean命名約定
約定是在命名bean時將標準Java約定用於實例字段名稱。
也就是說,bean名稱以小寫字母開頭,並從那裏用駝峯式大小寫。
這樣的名字的例子包括accountManager, accountService,userDao,loginController,等等。

一致地命名Bean使您的配置更易於閱讀和理解。
另外,若是您使用Spring AOP,則在將切點應用於名稱相關的一組bean時,它會頗有幫助。

經過在類路徑中進行組件掃描,Spring會按照前面描述的規則爲未命名的組件生成Bean名稱:本質上,採用簡單的類名稱並將其初始字符轉換爲小寫。
可是,在(不尋常的)特殊狀況下,若是有多個字符而且第一個和第二個字符均爲大寫字母,則會保留原始大小寫。
這些規則與java.beans.Introspector.decapitalize(由Spring在此處使用)定義的規則相同。
在Bean定義以外別名Bean

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

可是,在實際定義bean的地方指定全部別名並不老是足夠的。有時須要爲在別處定義的bean引入別名。在大型系統中一般是這種狀況,在大型系統中,配置在每一個子系統之間分配,每一個子系統都有本身的對象定義集。在基於XML的配置元數據中,您可使用<alias/>元素來完成此任務。如下示例顯示瞭如何執行此操做:

<alias name="fromName" alias="toName"/>
在這種狀況下,(在同一個容器中)名爲fromName的bean在使用了這個別名定義以後,也能夠被稱爲toName。

例如,
子系統A的配置元數據可能引用一個名爲subsystem-DataSource的數據源。
子系統B的配置元數據能夠引用名爲subsystembl-DataSource的數據源。
在編寫使用這兩個子系統的主應用程序時,主應用程序以myApp-dataSource的名稱引用數據源。
要讓這三個名稱引用同一個對象,您能夠在配置元數據中添加如下別名定義:

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

如今,每一個組件和主應用程序均可以經過惟一的名稱引用數據源,而且能夠保證不與任何其餘定義衝突(有效地建立名稱空間),可是它們引用的是同一bean。

Java-configuration

若是使用Java-configuration,則@Bean註解可用於提供別名。有關詳細信息,請參見使用@Bean註解。

1.3.2。實例化bean

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

若是使用基於XML的配置元數據,則能夠在元素的class屬性中指定要實例化的對象的類型(或類)<bean/>。此 class屬性(在內部是實例的Class屬性BeanDefinition)一般是必需的。

如下兩種狀況會用到Class屬性:

一般,在容器自己經過反射調用其構造函數直接建立bean的狀況下,
指定要構造的bean類,這在某種程度上等同於使用new操做符的Java代碼。

要指定包含爲建立對象而調用的靜態工廠方法的實際類,
在容器調用類上的靜態工廠方法來建立bean的狀況下就不太常見了。
從靜態工廠方法調用返回的對象類型能夠是相同的類,也能夠徹底是另外一個類。
內部類名稱
若是但願爲靜態嵌套類配置bean定義,則必須使用嵌套類的二進制名稱。

例如,若是你在com中有一個叫作什麼的類。
這個東西類有一個名爲OtherThing的靜態嵌套類,
bean定義上的class屬性的值將是com.example.SomeThing$OtherThing。

請注意名稱中使用了$字符來分隔嵌套的類名和外部類名。

<bean id="innerClass1" class="org.springframework.example.config.MyBean$InnerClass"/>
用構造函數實例化

當經過構造方法建立一個bean時,全部普通類均可以被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"/>

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:

<bean id="serviceLocator" class="examples.DefaultServiceLocator">
</bean>

<bean id="clientService"
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>

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

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文檔中,「 factory bean」是指在Spring容器中配置並經過實例或 靜態工廠方法建立對象的bean 。相反, FactoryBean(注意大寫)是指特定於Spring的 FactoryBean 實現類。

肯定Bean的運行時類型

肯定特定bean的運行時類型並不是易事。Bean元數據定義中的指定類只是初始類引用,可能與聲明的工廠方法結合使用,或者是FactoryBean可能致使Bean的運行時類型不一樣的類,或者在實例的狀況下根本不設置-級別工廠方法(經過指定factory-bean名稱解析)。另外,AOP代理可使用基於接口的代理包裝bean實例,而目標Bean的實際類型(僅是其實現的接口)的暴露程度有限。

找出特定bean的實際運行時類型的推薦方法是BeanFactory.getType調用指定的bean名稱。這考慮了上述全部狀況,並返回了BeanFactory.getBean要針對相同bean名稱返回的對象的類型。

相關文章
相關標籤/搜索