javascript
Spring Ioc (Inversion of Control)
2019獨角獸企業重金招聘Python工程師標準>>>
以下整理自http://jinnianshilongnian.iteye.com/blog/1413846,如有侵權立即刪除。
Ioc
Ioc(Inversion of Control),即控制反轉。不是什么技術,而是一種設計思想。在Java開發中,Ioc意味著將你設計好的對象交給容器控制,而不是傳統的在你的對象內部直接控制。 傳統Java SE程序設計,我們直接在對象內部通過new進行創建對象,是程序主動去創建依賴對象;而IoC是有專門一個容器來創建這些對象,即由Ioc容器來控制對象的創建;IoC 容器控制了對象(主要控制了外部資源獲取,不只是對象包括比如文件等)。
傳統應用程序是由我們自己在對象中主動控制去直接獲取依賴對象,也就是正轉;而反轉則是由容器來幫忙創建及注入依賴對象;為何是反轉?因為由容器幫我們查找及注入依賴對象,對象只是被動的接受依賴對象,所以是反轉;哪些方面反轉了?依賴對象的獲取被反轉了。
Ioc 容器
IoC容器就是具有依賴注入功能的容器,IoC容器負責實例化、定位、配置應用程序中的對象及建立這些對象間的依賴。應用程序無需直接在代碼中new相關的對象,應用程序由IoC容器進行組裝。在Spring中BeanFactory是IoC容器的實際代表者。
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);
(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");
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的位置。用于文件系統配置的讀取
HelloApi.java和HelloImpl.java是一個簡單的接口及其實現,打印一句Hello World!,bean.xml和fileSystemConfig.xml內容相同,都只有一句簡單的對bean的配置:<bean id="hello" class="cn.nevo.service.impl.HelloImpl"></bean>
測試代碼演示了使用不同的Ioc容器實現去讀取類路徑配置文件和文件系統文件的方式:
IoC容器到底是如何工作。在此我們以xml配置方式來分析一下:
一、準備配置文件:在配置文件中聲明Bean定義也就是為Bean配置元數據。
二、由IoC容器進行解析元數據: IoC容器的Bean Reader讀取并解析配置文件,根據定義生成BeanDefinition配置元數據對象,IoC容器根據BeanDefinition進行實例化、配置及組裝Bean。
三、實例化IoC容器:也就是實例化BeanFactory的各種實現,由客戶端實例化容器,獲取需要的Bean。
XML配置文件的結構
1、<bean>標簽主要用來進行Bean定義;
2、alias用于定義Bean別名的;
3、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主要有以下幾種方式:
1、使用構造器實例化Bean,這是最簡單的方式,Spring IoC容器即能使用默認空構造器也能使用有參數構造器兩種方式創建Bean
2、使用靜態工廠方式實例化Bean,使用這種方式除了指定必須的class屬性,還要指定factory-method屬性來指定實例化Bean的方法,而且使用靜態工廠方法也允許指定方法參數,spring IoC容器將調用此屬性指定的方法來獲取Bean
3、使用實例工廠方法實例化Bean,使用這種方式不能指定class屬性,此時必須使用factory-bean屬性來指定工廠Bean,factory-method屬性指定實例化Bean的方法,而且使用實例工廠方法允許指定方法參數,方式和使用構造器方式一樣
示例:
1、構造器實例化Bean:
bean.xml
<!-- 使用默認構造參數實例化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 {@Testpublic void testClassPathXmlApplicationContextBaseOnClassPath() {// 1.準備配置文件,從當前類加載路徑中獲取配置文件// 2.初始化容器BeanFactory beanFactory = new ClassPathXmlApplicationContext("bean.xml");// 2、從容器中獲取BeanHelloApi helloApi = beanFactory.getBean("hello", HelloApi.class);HelloApi helloApi2 = beanFactory.getBean("hello2", HelloApi.class);// 3、執行業務邏輯helloApi.sayHello();helloApi2.sayHello();} }
2、靜態工廠方式實例化Bean
返回HelloImpl實例的靜態工廠類HelloImplStaticFactory.java
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.xml
<!-- 使用靜態工廠方法實例化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();
3、實例工廠方式實例化Bean
用于產生HelloImpl實例的HelloImplInstanceFactory.java
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.xml
<!-- 使用實例工廠方法實例化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>
測試
轉載于:https://my.oschina.net/xiaomaoandhong/blog/69970
總結
以上是生活随笔為你收集整理的Spring Ioc (Inversion of Control)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AnkhSVN的自动加锁
- 下一篇: 基础概念总结(spring securi