IoC容器
本章介紹了Spring的控制反轉(IoC)容器。java
1.1。Spring IoC容器和Bean簡介
本章介紹了反轉控制(IoC)原則的Spring框架實現。
IoC也稱爲依賴注入(DI)。
在此過程當中,對象能夠經過①構造函數參數(),②工廠方法的參數③或在構造或從工廠方法返回後在對象實例上設置的屬性來定義其依賴項(即,與它們一塊兒使用的其餘對象) 。 而後,容器在建立bean時注入那些依賴項。linux
什麼叫作控制反轉? 舉例: 定義一個接口 CacheService.java 做爲頂級的緩存接口 定義 RedisCacheServiceImpl.java 實現redis緩存 定義 LocalCacheServiceImpl.java 實現本地緩存 這時候,若是沒有Spring框架的話那咱們的代碼 CacheService cache = new RedisCacheServiceImpl(); cache.set("xxx","xxx") ... ... 等到想替換其餘緩存方式的時候就改動代碼 CacheService cache = new LocalCacheServiceImpl(); 這也就是咱們說的面向接口編程,咱們寫代碼須要本身主動建立對象來引用不一樣的實現 可是IOC出現以後,代碼編寫就不同了,咱們直接拿Spring中代碼舉例: @Service("localCache") public class LocalCacheServiceImpl implements CacheService{} @Service("redisCache") public class RedisCacheServiceImpl implements CacheService{} @Autowired @Qualifier("redisCache") CacheService cache; 這樣編寫以後,new關鍵字不見了,多了一些陌生的註解, 簡單來講這些註解, @Service是把被標記了的服務告訴IOC容器, @Autowired是告訴IOC容器我想要引用什麼服務 當一個接口有多個實現類的時候咱們就須要 @Qualifier 來指定注入對應名稱的服務 經過解釋發現,咱們經過註解將服務都報告給了IOC容器,也經過註解引用了想要的服務。 也就是咱們所依賴對象的獲取方式被IOC容器控制了, 由以前的咱們主動建立對象到如今的IOC容器給咱們注入,這個過程就是 控制反轉
上邊只是演示了Spring IOC的一種方式注入對象
在org.springframework.beans和org.springframework.context包是Spring框架的IoC容器的基礎。
BeanFactory 接口提供了一種高級配置機制,可以管理任何類型的對象。 ApplicationContext 是BeanFactory的子接口。 它增長了:
與Spring的AOP功能輕鬆集成
消息資源處理(用於國際化)
事件發佈
應用層特定的上下文,例如WebApplicationContext 用於Web應用程序中的。redis
簡而言之,BeanFactory提供了配置框架和基本功能,並ApplicationContext增長了更多針對企業的功能。該ApplicationContext是對一個完整的超集BeanFactory,並在Spring的IoC容器的描述本章獨佔使用。spring
總的來講ApplicationContext是一個大而全的類,包括不少經常使用的功能, 只要獲取到容器中的ApplicationContext的對象就能夠直接獲取對象,發佈消息等,
在Spring中,構成應用程序主幹並由SpringIoC容器管理的對象稱爲bean。Bean是由Spring IoC容器實例化,組裝和以其餘方式管理的對象。不然,bean僅僅是應用程序中許多對象之一。Bean及其之間的依賴關係反映在容器使用的配置元數據中。編程
注意:註冊爲bean的對象才能夠用Spring的註解來注入它的依賴項
1.2。容器概述
該org.springframework.context.ApplicationContext接口表明Spring IoC容器,並負責實例化,配置和組裝Bean。容器經過讀取元數據配置來獲取有關要實例化,配置和組裝哪些對象的指令。配置元數據以XML,註解或Java代碼表示。它使您可以表達組成應用程序的對象以及這些對象之間的豐富相互依賴關係。json
幾種配置元數據的方式 ①xml <bean id="..." class="..."> ②註解 @Service @Component 等 ③java code @Configuration public class CommonConfig { @Bean public Validator validator(){} }
Spring提供了該接口(ApplicationContext)的幾種實現。在獨立應用程序中, 一般建立ClassPathXmlApplicationContext 或 FileSystemXmlApplicationContext的實例。儘管XML是定義元數據配置的傳統格式,可是您能夠經過提供少許XML配置來聲明性地啓用對這些其餘元數據格式的支持,從而指示容器將Java註解或代碼用做元數據格式。windows
Spring大方向來講是兩部分 首先全部的須要被註冊的bean,解析bean 而後實例化bean和解決依賴 ApplicationContext 各類實現類的區別其實就是第一步:查找和解析bean的方式有區別 好比有從xml中解析,有從Configuration類中解析,因此在當前解析方式上增長一些掃描路徑來實現其餘類型的元數據解析是徹底能夠的 好比:經過xml配置下邊一行 <context:component-scan base-package="org.springframework.example"/> 可讓Spring掃描org.springframework.example包下的帶註解的類,從而進行xml和註解的雙解析
1.2.1。配置元數據
Spring IoC容器使用元數據配置的方式來實現容器功能。此元數據的配置表示您做爲應用程序開發人員如何告訴Spring容器實例化,配置和組裝應用程序中的對象。緩存
傳統上,配置元數據以簡單直觀的XML格式提供,這是本章大部份內容用來傳達Spring IoC容器的關鍵概念和功能的內容。app
基於XML的元數據不是配置元數據的惟一容許形式。 Spring IoC容器自己與實際寫入此配置元數據的格式徹底脫鉤。現在,許多開發人員爲他們的Spring應用程序選擇基於Java的配置的方式(Spring 3.0開始)。框架
基於註解的配置:Spring 2.5引入了對基於註解的配置元數據的支持。 基於Java的配置:從Spring3.0開始,Spring JavaConfig項目提供的許多功能 成爲核心Spring Framework的一部分。 所以,您可使用Java而不是XML文件來定義應用程序類外部的bean。 要使用這些新功能,請參閱 @Configuration, @Bean, @Import,和@DependsOn註釋。
如下示例顯示了基於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="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> </beans> 該id屬性是標識單個bean定義的字符串。 該class屬性定義Bean的類型,並使用徹底限定的類名。 該id屬性的值是指協做對象。在此示例中未顯示用於引用協做對象的XML。有關更多信息,請參見 依賴項。
1.2.2。實例化容器
提供給ApplicationContext構造函數的一個或多個位置路徑是資源字符串,可以讓容器從各類外部資源(例如本地文件系統,Java CLASSPATH等)加載配置元數據。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
瞭解了Spring的IoC容器以後,您可能想了解更多有關Spring的 Resource抽象(如參考資料中所述),它提供了一種方便的機制,用於從URI語法中定義的位置讀取InputStream。具體而言,Resource如應用程序上下文和資源路徑中所述, 路徑用於構造應用程序上下文。
如下示例顯示了服務層對象(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"> <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl"> <property name="accountDao" ref="accountDao"/> <property name="itemDao" ref="itemDao"/> </bean> </beans>
如下示例顯示了數據訪問對象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"> </bean> <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao"> </bean> </beans>
在前面的示例中,服務層的PetStoreServiceImpl類由兩個數據訪問對象JpaAccountDao和JpaItemDao(基於JPA對象關係映射標準)組成。
該property name元素是指JavaBean屬性的名稱,以及ref元素指的是另外一個bean定義的名稱。id和ref元素之間的這種聯繫表達了協做對象之間的依賴性。
組裝基於XML的配置元數據
擁有多個XML文件可能頗有用。一般,每一個單獨的XML配置文件都表明體系結構中的邏輯層或模塊。
您可使用應用程序上下文構造函數從全部這些XML片斷中加載bean定義。
Resource如上一節中所示,該構造函數具備多個位置。或者,使用一個或多個出現的<import/>元素從另外一個文件中加載bean定義。如下示例顯示瞭如何執行此操做:
<beans> <import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> </beans>
在前面的例子中,外部bean定義是從三個文件加載: services.xml,messageSource.xml,和themeSource.xml。 全部位置路徑是相對於當前的定義文件來講的,所以services.xml相對於當前的文件路徑必須在同一個目錄或類路徑位置,而messageSource.xml並themeSource.xml必須在resources目錄下方的位置。 如您所見,斜槓被忽略。可是,鑑於這些路徑是相對的,最好不要使用任何斜線。
能夠但不建議使用相對的「../」路徑引用父目錄中的文件。這樣作會建立對當前應用程序外部文件的依賴關係。 特別是,不建議對classpath:URL(例如classpath:../services.xml)使用此引用,在URL 中,運行時解析過程會選擇「最近」的類路徑根, 而後查看其父目錄。類路徑配置的更改可能致使選擇其餘錯誤的目錄。 這段沒咋看懂,追了下源碼 // <import resource="classpath:../resources/bean.xml"/> //找到 resource 後邊的路徑 String location = ele.getAttribute("resource"); if (!StringUtils.hasText(location)) { getReaderContext().error("Resource location must not be empty", ele); return; } //補充路徑中的 $ 符包括的內容 e.g. "${user.dir}" location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); Set<Resource> actualResources = new LinkedHashSet<>(4); // 判斷當前url是不是絕對路徑仍是相對路徑 // classpath*: classpath: 開頭的都是絕對路徑 // 可以成功 new URL(location) 不報錯也是絕對路徑 // new URI(location).isAbsolute() 返回true也是絕對路徑 boolean absoluteLocation = false; try { absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException ex) { } if (absoluteLocation) { 絕對路徑就要判斷是否是 classpath*: 開頭 是classpath*: 開頭 一種解析方法 不然是另外一種解析方法 } else { }
您可使用絕對路徑來代替相對路徑:例如file:C:/config/services.xml或classpath:/config/services.xml。可是,請注意,您正在將應用程序的配置耦合到特定的絕對位置。最好爲這樣的絕對位置保留一個間接性—例如,經過「${…}」佔位符,這些佔位符在運行時根據JVM系統屬性解析。
好比應用名稱是application 文件爲 file.json 在windows下路徑爲 c:/myApp/application/file.json 在linux下問 /home/xxx/application/file.json 若是在代碼不變的狀況下,必須將 application文件名前半截的東西配置成可變的 ${prefixPath}/application/file.json 在運行是根據配置不一樣的變量找到不一樣的文件
命名空間自己提供了導入指令功能。Spring提供的一系列XML名稱空間(例如context和util名稱空間)中提供了超出普通bean定義的其餘配置功能。
beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"
1.2.3。使用容器
ApplicationContext是一個維護bean定義以及相互依賴的註冊表的高級工廠的接口。
使用方法 T getBean(String name, Class<T>requiredType),您能夠檢索bean的實例。
用ApplicationContext讀bean定義和訪問它們,以下例所示: // 讀取配置文件 建立bean ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml"); // 獲取bean對應的實例 PetStoreService service = context.getBean("petStore", PetStoreService.class); // 使用 List<String> userList = service.getUsernameList();
你能夠在相同的ApplicationContext上混合和匹配這些閱讀器,從不一樣的配置源讀取bean定義。
這句話我理解爲 同一個ApplicationContext 既支持讀取xml配置的Bean 也支持讀取註解註冊的Bean
而後,您能夠getBean用來檢索bean的實例。該ApplicationContext 接口還有其餘幾種檢索bean的方法,可是理想狀況下,您的應用程序代碼永遠不要使用它們。實際上,您的應用程序代碼應該根本不調用該 getBean()方法,所以徹底不依賴於Spring API。例如,Spring與Web框架的集成爲各類Web框架組件(例如控制器和JSF管理的Bean)提供了依賴注入,使您能夠經過元數據(例如自動裝配註釋)聲明對特定Bean的依賴。
通常狀況下開發簡單使用 @Autowired 徹底能夠作到自動注入了, 只有本身定製功能的時候可能會用到ApplicationContext中的方法
本文由博客羣發一文多發等運營工具平臺 OpenWrite 發佈