IoC容器是spring框架的核心組件骤素,spring通過IoC容器來管理所有Java對象及其相互間的依賴關(guān)系。
依賴注入(Dependency Injection,DI)和控制反轉(zhuǎn)的關(guān)系:
兩者其實是一個事物的兩種不同說法梦谜,本質(zhì)上是一回事。依賴注入是一個程序設(shè)計模式和架構(gòu)模型,也稱控制反轉(zhuǎn)碍现。在技術(shù)上來說依賴注入是一個控制反轉(zhuǎn)的特殊事項躏升,但依賴注入還指一個對象應(yīng)用另外一個對象來提供一個特殊的能力一睁。如把一個數(shù)據(jù)庫連接以參數(shù)的形式傳到一個對象的結(jié)構(gòu)方法里饲帅,而不是在那個對象內(nèi)部自行創(chuàng)建一個連接。
依賴注入和控制反轉(zhuǎn)的基本思想是把類的依賴從類內(nèi)部轉(zhuǎn)到外部以減少依賴。利用控制反轉(zhuǎn)按声,對象在被創(chuàng)建時渐裂,會由一個調(diào)控系統(tǒng)統(tǒng)一進行對象實例的隔離哈垢,將該對象鎖依賴對象的引用通過調(diào)控系統(tǒng)傳遞給它绑警,或者說被注入到對象中。控制反轉(zhuǎn)是關(guān)于一個對象如何獲取它所依賴對象的引用的過程,這個過程體現(xiàn)為”誰來傳遞依賴的引用“這個職責的反轉(zhuǎn)。
控制反轉(zhuǎn)的實現(xiàn)類型:依賴注入(Dependency Injection埋心,DI)和依賴查找(Dependency Lookup)晨横。其中依賴注入應(yīng)用較為廣泛手形,spring就是采用此方式來實現(xiàn)控制反轉(zhuǎn)的啥供。
IoC容器和bean概述
Spring通過IoC容器來管理所有Java對象及其之間的依賴關(guān)系伙狐。IoC解決了各個對象之間不需要直接關(guān)聯(lián)罢防,而在需要時由IoC容器來管理對象的依賴關(guān)系,開發(fā)者只需維護相對獨立的各個對象代碼即可硅确。
IoC是一個過程明肮,即對象定義及其依賴關(guān)系疏魏,其他與之配合的對象只能通過構(gòu)造函數(shù)、工廠方法參數(shù)官份、從工廠方法構(gòu)造或返回或在對象實例上設(shè)置的屬性來定義依賴關(guān)系只厘,然后IoC容器在創(chuàng)建bean時會注入這些依賴項。此過程在職責上是反轉(zhuǎn)的舅巷,即先把原來代碼中需要實現(xiàn)的對象創(chuàng)建羔味、依賴的代碼反轉(zhuǎn)給容器來實現(xiàn)和管理,故稱為控制反轉(zhuǎn)钠右。
IoC的應(yīng)用的設(shè)計模式:
1)反射:在程序運行狀態(tài)中根據(jù)提供的類路徑或類名赋元,通過反射來動態(tài)獲取該類所有的屬性及方法。
2)工廠模式:把IoC容器當做一個工廠飒房,在配置文件或注解中給出定義搁凸,然后利用反射技術(shù),根據(jù)給出的類名生成相應(yīng)的對象狠毯。對象生成的代碼和對象之間的依賴關(guān)系在配置?文件中定義护糖,以此實現(xiàn)解耦。
org.springframework.beans和org.springframework.context包是IoC容器的基礎(chǔ)嚼松,BeanFactory接口提供了能夠管理任何類型對象的高級配置機制嫡良,ApplicationContext是BeanFactory的子接口锰扶,它更易與AOP功能集成,進行消息資源處理寝受、事件發(fā)布坷牛、作為應(yīng)用層特定的上下文。
bean是由spring?IoC容器進行實例化很澄、組裝并管理的對象漓帅。它們之間的依賴關(guān)系反映在容器使用的配置元數(shù)據(jù)中。
配置元數(shù)據(jù)(Configuration Metadata)
配置元數(shù)據(jù)描述了spring容器在應(yīng)用程序中是如何提供實例化痴怨、配置和組裝對象的忙干。配置元數(shù)據(jù)的幾種方式:基于XML方式、基于注解浪藻、基于Java的配置捐迫。比較流行的是后兩種。
基于注解的配置:從spring2.5開始引入爱葵。
基于Java的配置:從spring3.0開始引入施戴。可以使用Java而不是XML文件來定義應(yīng)用程序類外部的bean萌丈。常用的注解有:@Configuration赞哗、@Bean、@Import辆雾、@DependsOn肪笋。
spring配置至少需要一個活多個由容器管理的bean《扔兀基于XML的方式藤乙,需要用到<beans/>元素內(nèi)的<bean/>元素來配置bean,在基于Java的配置中惭墓,通常在@Configuration注解的類中使用@Bean注解的方法坛梁。
在XML文件中,id屬性用于標識單個bean定義的字符串腊凶,它的值是指協(xié)作對象划咐,class屬性定義bean的類型,使用完全限定的類名钧萍。
實例化容器
spring?IoC容器需要在應(yīng)用啟動時進行實例化褐缠,在實例化過程中,IoC容器會從外部資源加載配置元數(shù)據(jù)划煮,提供給ApplicationContext構(gòu)造函數(shù)送丰。
ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"service.xml","dao.xml"}); //從類路徑中加載基于XML的配置元數(shù)據(jù)
當系統(tǒng)較大時缔俄,通常會將bean定義分到多個XML中弛秋,這樣每個XML配置文件可以表示系統(tǒng)中的邏輯層或模塊器躏。當某個構(gòu)造函數(shù)需要多個資源位置時,可以使用一個或多個<import/>從另外一個文件加載bean的定義蟹略。
使用容器
ApplicationContext是高級工廠的接口登失,可以維護不同的bean及其依賴項的注冊表。其中<T> T getBean(String var1, Class<T> var2)方法可以用于搜索bean實例挖炬。
正常情況下應(yīng)用程序不應(yīng)該使用ApplicationContext中的方法揽浙,因為程序代碼不需要調(diào)用getBean方法,就可以完全不依賴于spring API意敛。如spring與web框架集成馅巷,為各種web框架提供了依賴注入,它允許開發(fā)者通過元數(shù)據(jù)聲明對特定bean的依賴關(guān)系草姻。
bean的命名
每個bean都有一個或多個標識符钓猬,這些標識符在托管bean的容器中必須是唯一的。一個bean一般只有一個標識符撩独,如果需要多個標識符敞曹,額外的標識符會被當作是別名。
在基于XML的配置元數(shù)據(jù)中综膀,使用id或name屬性來指定bean標識符澳迫。id屬性允許指定一個id,這些標識符的名稱是字母或者包含特殊字符剧劝。如果向bean引入其他別名橄登,可以在name屬性中指定,用“讥此,”示绊、“;”暂论、空格分隔面褐。在spring3.1之前,id屬性被定義為一個xsd:ID類型取胎,限制了可能的字符展哭。之后的版本被定義為一個xsd:string類型。雖然更改了類型闻蛀,但bean的唯一性仍由容器強制執(zhí)行匪傍。
用戶可以不必為bean提供名稱或標識符,若沒有顯示的提供名稱或標識符觉痛,容器會為其自動生成唯一的名稱役衡。如果想通過名稱引用該bean,就必須提供一個名稱薪棒。
在bean的命名時盡量使用Java規(guī)范手蝎,即bean的名稱要遵循以一個小寫字母開頭的駝峰命名規(guī)則榕莺,如“userDao”、"indexController"棵介、"userService"等钉鸯。spring為未命名的組件生成bean名稱,同樣遵循上述原則邮辽。最簡單的命名方式就是直接采用類名稱并將其首字母改成小寫唠雕,但當前兩個字母都是大寫時可以不進行處理,如“URL”類bean的名稱仍然不變吨述。這些命名規(guī)則定義在java.beans.Introspector.decapitalize方法中岩睁。
實例化bean的方式
bean的實例化就是根據(jù)配置來創(chuàng)建對象的過程,主要有以下三種方式:
通過構(gòu)造函數(shù)實例化
Spring IoC容器可以管理所有想讓它管理的類揣云,如POJO笙僚、非bean形式的類等。當使用構(gòu)造方法來創(chuàng)建bean時灵再,對spring來說并無特殊之處肋层。根據(jù)所使用的IoC類型,可能需要一個默認(無參)的構(gòu)造方法翎迁。當使用XML配置方式時栋猖,可如下配置:
<bean id="myBean" class="com.xxx.service.MyBean" />
使用靜態(tài)工廠方法實例化
當使用靜態(tài)工廠方法創(chuàng)建bean時,除了指定class屬性外汪榔,還要通過factory-method屬性來指定創(chuàng)建bean實例的工廠方法蒲拉,spring將調(diào)研此方法返回實例對象。其實它和使用普通構(gòu)造器創(chuàng)建實例并無差別痴腌。示例如下:
<bean id="userService" class="com.xxx.service.UserService" />
public class?UserService {
? ? private static?UserService service = new?UserServiceImpl();
? ? private?UserService() {}
? ? public static?UserService createInstance() {return service;}
}
使用工廠實例方法實例化
通過調(diào)用工廠實例的非靜態(tài)方法進行實例化雌团,與通過靜態(tài)工廠方法實例化類似,使用時class屬性設(shè)置為空士聪,而factory-method屬性必須指定為當前/祖先容器中包含工廠方法的bean的名稱锦援,而該工廠bean的工廠方法本身須通過factory-method屬性來設(shè)定。示例如下:
<!--?工廠bean剥悟,包含createInstance()方法?-->
<bean id="serviceLocator" class="com.xxx.DefaultServiceLocator" >
? ??<!--?其他需要注入的依賴項 -->
</bean>
<!--?通過工廠bean創(chuàng)建的bean -->
<bean id="userService" factory-bean="serviceLocator"?
????factory-method="createUserServiceInstance" />
<bean id="accountService" factory-bean="serviceLocator"?
????factory-method="createAccountServiceInstance" />
public class?DefaultServiceLocator {
? ??private static?UserService userService = new?UserServiceImpl();
????private static?AccountService accService = new?AccountServiceImpl();
? ? private?DefaultServiceLocator() {}
? ? public?UserService??createUserServiceInstance() {return userService;}
? ? public AccountService??createAccountServiceInstance() {return?accService;}
}
--參考文獻《Srping5開發(fā)大全》