SpringFramework Core(一)

IoC容器

IoC也稱為依賴注入(DI)。在此過程中,對象僅通過構(gòu)造函數(shù)參數(shù),工廠方法的參數(shù)或在構(gòu)造或從工廠方法返回后在對象實例上設(shè)置的屬性來定義其依賴項(即,與它們一起使用的其他對象) 。然后,容器在創(chuàng)建bean時注入那些依賴項。此過程從根本上講是通過使用類的直接構(gòu)造或諸如服務(wù)定位器模式的機(jī)制來控制其依賴關(guān)系的實例化或位置的Bean本身的逆過程(因此稱為Control Inversion)。
org.springframework.beansorg.springframework.context包是Spring框架的IoC容器的基礎(chǔ)。 BeanFactory 提供了一種高級配置機(jī)制,能夠管理任何類型的對象。

ApplicationContextBeanFactory的子接口。它增加了:

  • 與Spring的AOP功能輕松集成

  • 消息資源處理(用于國際化)

  • 活動發(fā)布

  • 應(yīng)用層特定的上下文,例如WebApplicationContext 用于Web應(yīng)用程序中的。

在Spring中,構(gòu)成應(yīng)用程序主干并由Spring IoC容器管理的對象稱為bean。Bean是由Spring IoC容器實例化,組裝和以其他方式管理的對象。否則,bean僅僅是應(yīng)用程序中許多對象之一。Bean及其之間的依賴關(guān)系反映在容器使用的配置元數(shù)據(jù)中。

容器概述

org.springframework.context.ApplicationContext接口代表Spring IoC容器,并負(fù)責(zé)實例化,配置和組裝Bean。容器通過讀取配置元數(shù)據(jù)來獲取有關(guān)要實例化,配置和組裝哪些對象的指令。配置元數(shù)據(jù)以XML,Java批注或Java代碼表示。它使您能夠表達(dá)組成應(yīng)用程序的對象以及這些對象之間的豐富相互依賴關(guān)系。

ApplicationContextSpring提供了該接口的幾種實現(xiàn)。在獨立應(yīng)用程序中,通常創(chuàng)建ClassPathXmlApplicationContext 或的實例 FileSystemXmlApplicationContext。盡管XML是定義配置元數(shù)據(jù)的傳統(tǒng)格式,但是您可以通過提供少量XML配置來聲明性地啟用對這些其他元數(shù)據(jù)格式的支持,從而指示容器將Java注釋或代碼用作元數(shù)據(jù)格式。

下圖顯示了Spring的工作原理的高級視圖。您的應(yīng)用程序類與配置元數(shù)據(jù)結(jié)合在一起,因此,在ApplicationContext創(chuàng)建和初始化后,您將擁有一個完全配置且可執(zhí)行的系統(tǒng)或應(yīng)用程序。


image

配置元數(shù)據(jù)

如上圖所示,Spring IoC容器使用一種形式的配置元數(shù)據(jù)。這個配置元數(shù)據(jù)表示您作為應(yīng)用程序開發(fā)人員如何告訴Spring容器實例化,配置和組裝應(yīng)用程序中的對象。

傳統(tǒng)上,配置元數(shù)據(jù)以簡單直觀的XML格式提供,這是本章大部分內(nèi)容用來傳達(dá)Spring IoC容器的關(guān)鍵概念和功能的內(nèi)容。

基于XML的元數(shù)據(jù)不是配置元數(shù)據(jù)的唯一允許形式。Spring IoC容器本身與實際寫入此配置元數(shù)據(jù)的格式完全脫鉤。如今,許多開發(fā)人員為他們的Spring應(yīng)用程序選擇 基于Java的配置。

有關(guān)在Spring容器中使用其他形式的元數(shù)據(jù)的信息,請參見:

  • 基于注釋的配置:Spring 2.5引入了對基于注釋的配置元數(shù)據(jù)的支持。

  • 基于Java的配置:從Spring 3.0開始,Spring JavaConfig項目提供的許多功能成為核心Spring Framework的一部分。因此,您可以使用Java而不是XML文件來定義應(yīng)用程序類外部的bean。要使用這些新功能,請參閱 @Configuration@Bean, @Import,和@DependsOn注釋。

基于XML的配置元數(shù)據(jù)將這些bean配置為<bean/>頂級元素內(nèi)的<beans/>元素。Java配置通常@Bean在@Configuration類中使用帶注釋的方法。

這些bean定義對應(yīng)于組成應(yīng)用程序的實際對象。通常,您定義服務(wù)層對象,數(shù)據(jù)訪問對象(DAO),表示對象(例如Struts Action實例),基礎(chǔ)結(jié)構(gòu)對象(例如Hibernate SessionFactories,JMS Queues等)。

以下示例顯示了基于XML的配置元數(shù)據(jù)的基本結(jié)構(gòu):

<?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
        https://www.springframework.org/schema/beans/spring-beans.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>

該id屬性是標(biāo)識單個bean定義的字符串。
該class屬性定義Bean的類型,并使用完全限定的類名。

實例化容器

提供給ApplicationContext構(gòu)造函數(shù)的位置路徑是資源字符串,這些資源字符串使容器可以從各種外部資源(例如本地文件系統(tǒng),Java等)加載配置元數(shù)據(jù)CLASSPATH。

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

以下示例顯示了服務(wù)層對象(services.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- services -->

    <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
        <property name="accountDao" ref="accountDao"/>
        <property name="itemDao" ref="itemDao"/>
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions for services go here -->

</beans>

以下示例顯示了數(shù)據(jù)訪問對象daos.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="accountDao"
        class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions for data access objects go here -->

</beans>

在前面的示例中,服務(wù)層由的PetStoreServiceImpl類和類型的兩個數(shù)據(jù)訪問對象JpaAccountDao和JpaItemDao(基于JPA對象關(guān)系映射標(biāo)準(zhǔn))。該property name元素是指JavaBean屬性的名稱,以及ref元素指的是另一個bean定義的名稱。id和ref元素之間的這種聯(lián)系表達(dá)了協(xié)作對象之間的依賴性。

組成基于XML的配置元數(shù)據(jù)

使bean定義跨越多個XML文件可能很有用。通常,每個單獨的XML配置文件都代表體系結(jié)構(gòu)中的邏輯層或模塊。

可以使用應(yīng)用程序上下文構(gòu)造函數(shù)從所有這些XML片段中加載bean定義。Resource如上一節(jié)中所示,此構(gòu)造函數(shù)具有多個位置 ?;蛘?,使用一個或多個出現(xiàn)的<import/>元素從另一個文件中加載bean定義。以下示例顯示了如何執(zhí)行此操作:

<beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>

    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>

在前面的例子中,外部豆定義是從三個文件加載: services.xml,messageSource.xml,和themeSource.xml。所有位置路徑是相對于定義文件做進(jìn)口,因此services.xml必須在同一個目錄或類路徑位置作為文件做進(jìn)口,而 messageSource.xml并themeSource.xml必須在resources進(jìn)口文件的位置下方的位置。如您所見,斜杠被忽略。但是,鑒于這些路徑是相對的,最好不要使用任何斜線。<beans/>根據(jù)Spring Schema,導(dǎo)入的文件的內(nèi)容(包括頂層元素)必須是有效的XML bean定義。

使用容器

ApplicationContext是一個維護(hù)bean定義以及相互依賴的注冊表的高級工廠的接口。通過使用方法T getBean(String name, Class<T> requiredType),您可以檢索bean的實例。

// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// use configured instance
List<String> userList = service.getUsernameList();

后,您可以getBean用來檢索bean的實例。該ApplicationContext 接口還有其他幾種檢索bean的方法,但是理想情況下,您的應(yīng)用程序代碼永遠(yuǎn)不要使用它們。實際上,您的應(yīng)用程序代碼應(yīng)該根本不調(diào)用該 getBean()方法,因此完全不依賴于Spring API。例如,Spring與Web框架的集成為各種Web框架組件(例如控制器和JSF管理的Bean)提供了依賴項注入,使您可以通過元數(shù)據(jù)(例如自動裝配注釋)聲明對特定Bean的依賴項。

Bean總覽

Spring IoC容器管理一個或多個bean。這些bean是使用您提供給容器的配置元數(shù)據(jù)創(chuàng)建的。

在容器本身內(nèi),這些bean定義表示為BeanDefinition 對象,其中包含(除其他信息外)以下元數(shù)據(jù):

包限定的類名:通常,定義了Bean的實際實現(xiàn)類。

Bean行為配置元素,用于聲明Bean在容器中的行為(作用域,生命周期回調(diào)等)。

對其他bean進(jìn)行工作所需的引用。這些引用也稱為協(xié)作者或依賴項。

要在新創(chuàng)建的對象中設(shè)置的其他配置設(shè)置,例如,池的大小限制或要在管理連接池的bean中使用的連接數(shù)。

Bean定義:

  • 類 Class
  • 名稱 Name
  • scope 作用范圍
  • 構(gòu)造函數(shù)參數(shù) Constructor arguments
  • 屬性 Properties
  • 裝配模式 Autowiring mode
  • 延遲初始化
  • 初始化方法
  • 銷毀方法

除了包含有關(guān)如何創(chuàng)建特定bean的信息的bean定義之外,這些ApplicationContext實現(xiàn)還允許注冊在容器外部(由用戶)創(chuàng)建的現(xiàn)有對象。這是通過ApplicationContext的getBeanFactory()來完成的,該方法返回BeanFactory。BeanFactory 通過registerSingleton(..)和 registerBeanDefinition(..)方法支持此注冊。但是,典型的應(yīng)用程序只能與通過常規(guī)bean定義元數(shù)據(jù)定義的bean一起使用。

Bean元數(shù)據(jù)和手動提供的單例實例需要盡早注冊,以便容器在自動裝配和其他自省步驟中正確地推理它們。盡管在某種程度上支持覆蓋現(xiàn)有元數(shù)據(jù)和現(xiàn)有單例實例,但官方不支持在運行時(與對工廠的實時訪問同時)對新bean的注冊,并且可能導(dǎo)致并發(fā)訪問異常,bean容器中的狀態(tài)不一致。

Bean命名

每個bean具有一個或多個標(biāo)識符。這些標(biāo)識符在承載Bean的容器內(nèi)必須是唯一的。一個bean通常只有一個標(biāo)識符。但是,如果需要多個,則可以將多余的名字視為別名。

在基于XML配置文件,您可以使用id屬性,該name屬性,或兩者來指定bean標(biāo)識符。該id屬性使您可以精確指定一個ID。按照慣例,這些名稱是字母數(shù)字(“ myBean”,“ someService”等),但它們也可以包含特殊字符。如果要為bean引入其他別名,還可以在name 屬性中指定它們,并用逗號(,),分號(;)或空格分隔。作為歷史記錄,在Spring 3.1之前的版本中,該id屬性被定義為一種xsd:ID類型,該類型限制了可能的字符。從3.1開始,它被定義為xsd:string類型。請注意,Bean id唯一性仍由容器強制執(zhí)行,盡管不再由XML解析器執(zhí)行。

您不需要為bean 提供nameid。如果不提供 nameid顯式提供,容器將為該bean生成一個唯一的名稱。但是,如果要通過名稱引用該bean,則通過使用ref元素或 服務(wù)定位器樣式查找,必須提供一個名稱。不提供名稱的動機(jī)與使用內(nèi)部bean自動裝配合作者有關(guān)。

Bean命名約定
約定是在命名bean時將標(biāo)準(zhǔn)Java約定用于實例字段名稱。也就是說,bean名稱以小寫字母開頭,并從那里用駝峰式大小寫。這樣的名字的例子包括accountManager, accountService,userDao,loginController,等等。

一致地命名Bean使您的??配置更易于閱讀和理解。另外,如果您使用Spring AOP,則在將建議應(yīng)用于名稱相關(guān)的一組bean時,它會很有幫助。

在Bean定義之外別名Bean

在bean定義本身中,可以通過使用id屬性指定的最多一個名稱和該屬性中任意數(shù)量的其他名稱的組合來為bean提供多個名稱name。這些名稱可以是同一bean的等效別名,并且在某些情況下很有用,例如通過使用特定于該組件本身的bean名稱,讓應(yīng)用程序中的每個組件都引用一個公共依賴項。

但是,在實際定義bean的地方指定所有別名并不總是足夠的。有時需要為在別處定義的bean引入別名。這在大型系統(tǒng)中通常是這種情況,在大型系統(tǒng)中,配置在每個子系統(tǒng)之間分配,每個子系統(tǒng)都有自己的對象定義集。在基于XML的配置元數(shù)據(jù)中,您可以使用<alias/>元素來完成此任務(wù)。以下示例顯示了如何執(zhí)行此操作:

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

在這種情況下,在使用該別名定義之后,命名為fromName 的Bean(位于同一容器中)的Bean也可以稱為toName。

例如,子系統(tǒng)A的配置元數(shù)據(jù)可以通過名稱引用數(shù)據(jù)源subsystemA-dataSource。子系統(tǒng)B的配置元數(shù)據(jù)可以使用的名稱引用數(shù)據(jù)源subsystemB-dataSource。組成使用這兩個子系統(tǒng)的主應(yīng)用程序時,主應(yīng)用程序使用名稱引用數(shù)據(jù)源myApp-dataSource。要使所有三個名稱都引用同一個對象,可以將以下別名定義添加到配置元數(shù)據(jù)中:

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

現(xiàn)在,每個組件和主應(yīng)用程序都可以通過唯一的名稱引用數(shù)據(jù)源,并保證不會與任何其他定義沖突(有效地創(chuàng)建名稱空間),但它們引用的是同一bean。

實例化Bean

Bean定義本質(zhì)上是創(chuàng)建一個或多個對象的方法。容器在被詢問時會查看命名bean的配方,并使用該bean定義封裝的配置元數(shù)據(jù)來創(chuàng)建(或獲?。嶋H對象。

如果使用基于XML的配置元數(shù)據(jù),則可以在<bean/>元素的class屬性中指定要實例化的對象的類型(或類)。此 class屬性(在內(nèi)部是BeanDefinition 實例的Class屬性)通常是必需的。

可以通過以下兩種方式之一使用該Class屬性:

通常,在容器本身通過反射性地調(diào)用其構(gòu)造函數(shù)直接創(chuàng)建Bean的情況下,指定要構(gòu)造的Bean類,這在某種程度上等同于使用new運算符的Java代碼。

要指定包含要創(chuàng)建對象而調(diào)用的static工廠方法的實際類,在不太常見的情況下,容器將在類上調(diào)用 static工廠方法來創(chuàng)建Bean。從static工廠方法的調(diào)用返回的對象類型可以是同一類,也可以是完全不同的另一類。

用構(gòu)造函數(shù)實例化

當(dāng)通過構(gòu)造方法創(chuàng)建一個bean時,所有普通類都可以被Spring使用并與之兼容。也就是說,正在開發(fā)的類不需要實現(xiàn)任何特定的接口或以特定的方式進(jìn)行編碼。只需指定bean類就足夠了。但是,根據(jù)您用于該特定bean的IoC的類型,您可能需要一個默認(rèn)(空)構(gòu)造函數(shù)。

Spring IoC容器幾乎可以管理您要管理的任何類。它不僅限于管理真正的JavaBean。大多數(shù)Spring用戶更喜歡僅具有默認(rèn)(無參數(shù))構(gòu)造函數(shù)以及根據(jù)容器中的屬性建模的適當(dāng)?shù)膕etter和getter的實際JavaBean。您還可以在容器中具有更多奇特的非bean樣式類。例如,如果您需要使用絕對不符合JavaBean規(guī)范的舊式連接池,則Spring也可以對其進(jìn)行管理。

使用基于XML的配置元數(shù)據(jù),您可以如下指定bean類:

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

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

有關(guān)向構(gòu)造函數(shù)提供參數(shù)(如果需要)并在構(gòu)造對象之后設(shè)置對象實例屬性的機(jī)制的詳細(xì)信息,請參見 注入依賴項

用靜態(tài)工廠方法實例化

在定義使用靜態(tài)工廠方法創(chuàng)建的bean時,請使用class 屬性來指定包含static工廠方法的類,并使用命名factory-method為屬性的屬性來指定工廠方法本身的名稱。您應(yīng)該能夠調(diào)用此方法(帶有可選參數(shù),如后面所述),并返回一個活動對象,該對象隨后將被視為已通過構(gòu)造函數(shù)創(chuàng)建。這種bean定義的一種用法是static用舊版代碼調(diào)用工廠。

以下bean定義指定通過調(diào)用工廠方法來創(chuàng)建bean。該定義不指定返回對象的類型(類),而僅指定包含工廠方法的類。在此示例中,該createInstance() 方法必須是靜態(tài)方法。以下示例顯示如何指定工廠方法:

<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;
    }
}

使用實例工廠方法實例化

使用實例工廠方法實例化從容器中調(diào)用現(xiàn)有bean的非靜態(tài)方法以創(chuàng)建新bean。

要使用此機(jī)制,請將class屬性保留為空,并在factory-bean屬性中指定當(dāng)前(或父容器或祖先容器)中包含要創(chuàng)建對象的實例方法的Bean的名稱。使用factory-method屬性設(shè)置工廠方法本身的名稱。以下示例顯示了如何配置此類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"/>

以下示例顯示了相應(yīng)的類:

public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}

這種方法表明,F(xiàn)actory Bean本身可以通過依賴項注入(DI)進(jìn)行管理和配置。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容