如下整理自http://jinnianshilongnian.iteye.com/blog/1413846,若有侵權當即刪除。
Iochtml
Ioc(Inversion of Control),即控制反轉。不是什麼技術,而是一種設計思想。在Java開發中,Ioc意味着將你設計好的對象交給容器控制,而不是傳統的在你的對象內部直接控制。 傳統Java SE程序設計,咱們直接在對象內部經過new進行建立對象,是程序主動去建立依賴對象;而IoC是有專門一個容器來建立這些對象,即由Ioc容器來控制對象的建立;IoC 容器控制了對象(主要控制了外部資源獲取,不僅是對象包括好比文件等)。
傳統應用程序是由咱們本身在對象中主動控制去直接獲取依賴對象,也就是正轉;而反轉則是由容器來幫忙建立及注入依賴對象;爲什麼是反轉?由於由容器幫咱們查找及注入依賴對象,對象只是被動的接受依賴對象,因此是反轉;哪些方面反轉了?依賴對象的獲取被反轉了。
Ioc 容器java
IoC容器就是具備依賴注入功能的容器,IoC容器負責實例化、定位、配置應用程序中的對象及創建這些對象間的依賴。應用程序無需直接在代碼中new相關的對象,應用程序由IoC容器進行組裝。在Spring中BeanFactory是IoC容器的實際表明者。web
Spring IoC容器如何知道哪些是它管理的對象呢?這就須要配置文件,Spring IoC容器經過讀取配置文件中的配置元數據,經過元數據對應用中的各個對象進行實例化及裝配。通常使用基於xml配置文件進行配置元數據,並且Spring與配置文件徹底解耦的,可使用其餘任何可能的方式進行配置元數據,好比註解、基於java文件的、基於屬性文件的配置均可以。
Spring Ioc容器的表明就是org.springframework.beans包中的BeanFactory接口,BeanFactory接口提供了IoC容器最基本功能;而org.springframework.context包下的ApplicationContext接口擴展了BeanFactory,還提供了與Spring AOP集成、國際化處理、事件傳播及提供不一樣層次的context實現 (如針對web應用的WebApplicationContext)。簡單說, BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 則增長了更多支持企業級功能支持。ApplicationContext徹底繼承BeanFactory,於是BeanFactory所具備的語義也適用於ApplicationContext。
容器實現一覽:
• XmlBeanFactory:BeanFactory實現,提供基本的IoC容器功能,能夠從classpath或文件系統等獲取資源;
(1) File file = new File("fileSystemConfig.xml");
Resource resource = new FileSystemResource(file);
BeanFactory beanFactory = new XmlBeanFactory(resource);spring
(2)Resource resource = new ClassPathResource("classpath.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Deprecated. as of Spring 3.1 in favor of DefaultListableBeanFactory
and XmlBeanDefinitionReader
編程
• ClassPathXmlApplicationContext:ApplicationContext實現,從classpath獲取配置文件;
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath.xml");數組
• FileSystemXmlApplicationContext:ApplicationContext實現,從文件系統獲取配置文件。
BeanFactory beanFactory = new FileSystemXmlApplicationContext("fileSystemConfig.xml");
ide
ApplicationContext接口獲取Bean方法簡介:測試
• Object getBean(String name) 根據名稱返回一個Bean,客戶端須要本身進行類型轉換;
• T getBean(String name, Class<T> requiredType) 根據名稱和指定的類型返回一個Bean,客戶端無需本身進行類型轉換,若是類型轉換失敗,容器拋出異常;
• T getBean(Class<T> requiredType) 根據指定的類型返回一個Bean,客戶端無需本身進行類型轉換,若是沒有或有多於一個Bean存在容器將拋出異常;
• Map<String, T> getBeansOfType(Class<T> type) 根據指定的類型返回一個鍵值爲名字和值爲Bean對象的 Map,若是沒有Bean對象存在則返回空的Map。
示例:
項目結構圖,注意fileSystemConfig.xml的位置。用於文件系統配置的讀取
ui
HelloApi.java和HelloImpl.java是一個簡單的接口及其實現,打印一句Hello World!,bean.xml和fileSystemConfig.xml內容相同,都只有一句簡單的對bean的配置:<bean id="hello" class="cn.nevo.service.impl.HelloImpl"></bean>
測試代碼演示了使用不一樣的Ioc容器實現去讀取類路徑配置文件和文件系統文件的方式:
this
public class HelloServiceTest { @SuppressWarnings("deprecation") @Test public void testXmlBeanFactoryBaseOnFileSystem() { // 1.準備配置文件,從文件系統獲取配置文件,默認是相對路徑,能夠指定絕對路徑 File file = new File("fileSystemConfig.xml"); Resource resource = new FileSystemResource(file); // 2.初始化容器 BeanFactory beanFactory = new XmlBeanFactory(resource); // 二、從容器中獲取Bean HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class); // 三、執行業務邏輯 helloApi.sayHello(); } @SuppressWarnings("deprecation") @Test public void testXmlBeanFactoryBaseOnClassPath() { // 1.準備配置文件,從當前類加載路徑中獲取配置文件 Resource resource = new ClassPathResource("bean.xml"); // 2.初始化容器 BeanFactory beanFactory = new XmlBeanFactory(resource); // 二、從容器中獲取Bean HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class); // 三、執行業務邏輯 helloApi.sayHello(); } @Test public void testClassPathXmlApplicationContextBaseOnClassPath() { // 1.準備配置文件,從當前類加載路徑中獲取配置文件 // 2.初始化容器 BeanFactory beanFactory = new ClassPathXmlApplicationContext("bean.xml"); // 二、從容器中獲取Bean HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class); // 三、執行業務邏輯 helloApi.sayHello(); } @Test public void testFileSystemApplicationContextBaseOnFileSystem() { // 1.準備配置文件,從文件系統獲取配置文件,默認是相對路徑,能夠指定絕對路徑 // 2.初始化容器 BeanFactory beanFactory = new FileSystemXmlApplicationContext( "fileSystemConfig.xml"); // 二、從容器中獲取Bean HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class); // 三、執行業務邏輯 helloApi.sayHello(); } }
XML配置文件的結構
<beans> <import resource=」resource1.xml」/> <bean id=」bean1」class=」」></bean> <bean id=」bean2」class=」」></bean> <bean name=」bean2」class=」」></bean> <alias alias="bean3" name="bean2"/> <import resource=」resource2.xml」/> </beans>
一、<bean>標籤主要用來進行Bean定義;
二、alias用於定義Bean別名的;
三、import用於導入其餘配置文件的Bean定義,這是爲了加載多個配置文件,固然也能夠把這些配置文件構造爲一個數組(new String[] {「config1.xml」, config2.xml})傳給ApplicationContext實現進行加載多個配置文件,那一個更適合由用戶決定;這兩種方式都是經過調用Bean Definition Reader 讀取Bean定義,內部實現沒有任何區別。<import>標籤能夠放在<beans>下的任何位置,沒有順序關係。
Bean
由IoC容器管理的那些組成你應用程序的對象咱們就叫它Bean, Bean就是由Spring容器初始化、裝配及管理的對象,除此以外,bean就與應用程序中的其餘對象沒有什麼區別了。那IoC怎樣肯定如何實例化Bean、管理Bean之間的依賴關係以及管理Bean呢?這就須要配置元數據,在Spring中由BeanDefinition表明,後邊會詳細介紹,配置元數據指定如何實例化Bean、如何組裝Bean等。
Bean的配置
Spring IoC容器目的就是管理Bean,這些Bean將根據配置文件中的Bean定義進行建立,而Bean定義在容器內部由BeanDefinition對象表示,該定義主要包含如下信息:
● 全限定類名(FQN):用於定義Bean的實現類;
● Bean行爲定義:這些定義了Bean在容器中的行爲;包括做用域(單例、原型建立)、是否惰性初始化及生命週期等;
● Bean建立方式定義:說明是經過構造器仍是工廠方法建立Bean;
● Bean之間關係定義:即對其餘bean的引用,也就是依賴關係定義,這些引用bean也能夠稱之爲同事bean 或依賴bean,也就是依賴注入。
Bean定義只有「全限定類名」在當使用構造器或靜態工廠方法進行實例化bean時是必須的,其餘都是可選的定義。難道Spring只能經過配置方式來建立Bean嗎?回答固然不是,某些SingletonBeanRegistry接口實現類實現也容許將那些非BeanFactory建立的、已有的用戶對象註冊到容器中,這些對象必須是共享的,好比使用DefaultListableBeanFactory 的registerSingleton() 方法。不過建議採用元數據定義。
BeanDefinition
spring能夠經過xml配置文件定義bean,beanFactory能夠建立、查找配置文件中定義的這些bean,spring內部是如何將配置文件中所定義的bean變成可讓beanFactory建立與管理的呢?這是依靠BeanDefinition進行實現。BeanDefinition是一個接口,它描述了一個bean的實例,保存了bean的定義信息,是bean在內存中的描述形式。xml配置文件所定義的每一個bean在內存中都有對應的Bedifinition對象進行描述。BeanFactory在查找,建立及管理bean時,會先查找其在內存中所保存的BeanDefinition,而後再根據BeanDefinition中的bean描述內容建立bean或返回所需的bean信息。
根據面向接口編程的原則,spring定義了接口BeanDefinitionRegistry註冊管理全部的Bedifinition,實現此接口就能夠管理bean的定義,DefaultListableBeanFactory類實現了此接口,所以DefaultListableBeanFactory類及其子類具備管理beanDefinition的功能。
Spring讀取分析配置文件,根據配置文件中的定義,爲這些bean建立對應的BeanDifinition,並將BeanDifinition註冊至beanFactory中(具體表現爲註冊在DefaultListableBeanFactory類型的beanFactory)。當用戶須要使用bean時,將傳入bean的名稱或類型給beanFactory,beanFactory從其所保存的beanDefinition中查找,當找到符合條件的beanDefinition後,則將根據beanDefinition中的bean信息建立bean對象,並返回給用戶。
實例化Bean
Spring IoC容器如何實例化Bean呢?
傳統應用程序能夠經過new和反射方式進行實例化Bean。而Spring IoC容器則須要根據Bean定義裏的配置元數據使用反射機制來建立Bean。在Spring IoC容器中根據Bean定義建立Bean主要有如下幾種方式:
一、使用構造器實例化Bean,這是最簡單的方式,Spring IoC容器即能使用默認空構造器也能使用有參數構造器兩種方式建立Bean
二、使用靜態工廠方式實例化Bean,使用這種方式除了指定必須的class屬性,還要指定factory-method屬性來指定實例化Bean的方法,並且使用靜態工廠方法也容許指定方法參數,spring IoC容器將調用此屬性指定的方法來獲取Bean
三、使用實例工廠方法實例化Bean,使用這種方式不能指定class屬性,此時必須使用factory-bean屬性來指定工廠Bean,factory-method屬性指定實例化Bean的方法,並且使用實例工廠方法容許指定方法參數,方式和使用構造器方式同樣
示例:
一、構造器實例化Bean:
package cn.nevo.service.impl; import cn.nevo.service.HelloApi; public class HelloImpl implements HelloApi { private String message; public HelloImpl() { this.message = "Hello World!"; } public HelloImpl(String message) { this.message = message; } @Override public void sayHello() { System.out.println(message); } }
<!-- 使用默認構造參數實例化bean --> <bean id="hello" class="cn.nevo.service.impl.HelloImpl"></bean> <!-- 使用有參構造參數實例化bean --> <bean id="hello2" class="cn.nevo.service.impl.HelloImpl"> <constructor-arg index="0" value="New Hello World!"/> </bean>
public class HelloServiceTest { @Test public void testClassPathXmlApplicationContextBaseOnClassPath() { // 1.準備配置文件,從當前類加載路徑中獲取配置文件 // 2.初始化容器 BeanFactory beanFactory = new ClassPathXmlApplicationContext("bean.xml"); // 二、從容器中獲取Bean HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class); HelloApi helloApi2 = beanFactory.getBean("hello2", HelloApi.class); // 三、執行業務邏輯 helloApi.sayHello(); helloApi2.sayHello(); } }
package cn.nevo.service.impl.staticfactory; import cn.nevo.service.HelloApi; import cn.nevo.service.impl.HelloImpl; public class HelloImplStaticFactory { public static HelloApi getInstance(String message) { return new HelloImpl(message); } }
<!-- 使用靜態工廠方法實例化bean --> <bean id="statichello" class="cn.nevo.service.impl.staticfactory.HelloImplStaticFactory" factory-method="getInstance"> <constructor-arg index="0" value="static factory instance"/> </bean>
HelloApi helloApi3 = beanFactory.getBean("statichello", HelloApi.class); helloApi3.sayHello();
package cn.nevo.service.impl.instancefactory; import cn.nevo.service.HelloApi; import cn.nevo.service.impl.HelloImpl; public class HelloImplInstanceFactory { public HelloApi getInstance(String message) { return new HelloImpl(message); } }
<!-- 使用實例工廠方法實例化bean --> <bean id="instancehello" class="cn.nevo.service.impl.instancefactory.HelloImplInstanceFactory"/> <bean id="instance" factory-bean="instancehello" factory-method="getInstance"> <constructor-arg index="0" value="instance factory"/> </bean>
測試
HelloApi helloApi4 = beanFactory.getBean("instance", HelloApi.class); helloApi4.sayHello();