框架封裝了普通項目中程序員需要重復書寫的代碼和調用過程,就比如說在傳統的jsp項目中,我們的controller接收到前端的請求然后程序員就需要去開發Dao層,里面還涉及數據庫的連接和存儲過程的代碼,大部分都是冗余的代碼,而有了SSM框架后極大的簡化了程序猿在controller以下層的開發,只需要一個service層和mapper層就行了,mapper層用來連接mapper.xml文件的,而直接用mapper.xml做sql語句的開發就行了,而數據庫連接的和存儲的過程都直接由Mybatis負責了,你只需要負責傳遞形參和接收返回數據就行了,這樣就完成了一次完整的數據庫交互!
1.1、IoC是什么
Ioc—Inversion of Control,即“控制反轉”,不是什么技術,而是一種設計思想。在Java開發中,Ioc意味着將你設計好的對象交給容器控制,而不是傳統的在你的對象內部直接控制。如何理解好Ioc呢?理解好Ioc的關鍵是要明確“誰控制誰,控制什么,為何是反轉,哪些方面反轉了”,那我們來深入分析一下:
●誰控制誰,控制什么:傳統Java SE程序設計,我們直接在對象內部通過new進行創建對象,是程序主動去創建依賴對象;而IoC是有專門一個容器來創建這些對象,即由Ioc容器來控制對象的創建;誰控制誰?當然是IoC 容器控制了對象;控制什么?那就是主要控制了外部資源獲取(不只是對象包括比如文件等)。
●為何是反轉,哪些方面反轉了:有反轉就有正轉,傳統應用程序是由我們自己在對象中主動控制去直接獲取依賴對象,也就是正轉;而反轉則是由容器來幫忙創建及注入依賴對象;為何是反轉?因為由容器幫我們查找及注入依賴對象,對象只是被動的接受依賴對象,所以是反轉;哪些方面反轉了?依賴對象的獲取被反轉了。
用圖例說明一下,傳統程序設計如下圖,都是主動去創建相關對象然后再組合起來:
當有了IoC/DI的容器后,在客戶端類中不再主動去創建這些對象了,如下圖所示:
1.2 IoC能做什么
IoC不是一種技術,只是一種思想,一個重要的面向對象編程的法則,它能指導我們如何設計出松耦合、更優良的程序。傳統應用程序都是由我們在類內部主動創建依賴對象,從而導致類與類之間高耦合,難於測試;有了IoC容器后,把創建和查找依賴對象的控制權交給了容器,由容器進行注入組合對象,所以對象與對象之間是松散耦合,這樣也方便測試,利於功能復用,更重要的是使得程序的整個體系結構變得非常靈活。
其實IoC對編程帶來的最大改變不是從代碼上,而是從思想上,發生了“主從換位”的變化。應用程序原本是老大,要獲取什么資源都是主動出擊,但是在IoC/DI思想中,應用程序就變成被動的了,被動的等待IoC容器來創建並注入它所需要的資源了。
IoC的原理是基於好萊塢法則:“別找我們,我們找你(don‘t call us, we‘ll call you)”,即由IoC容器幫對象找相應的依賴對象並注入,而不是由對象主動去找。所有的組件都是被動的(Passive),所有的組件初始化和調用都由容器負責。
1.3 IoC和DI
DI—Dependency Injection,即“依賴注入”:是組件之間依賴關系由容器在運行期決定,形象的說,即由容器動態地將某個依賴關系注入到組件之中。依賴注入的目的並非為軟件系統帶來更多功能,而是為了提升組件重用的頻率,並為系統搭建一個靈活、可擴展的平台。通過依賴注入機制,我們只需要通過簡單的配置,而無需任何代碼就可指定目標需要的資源,完成自身的業務邏輯,而不需要關心具體的資源來自何處,由誰實現。
Spring IoC容器的依賴有兩層含義:Bean依賴容器和容器注入Bean的依賴資源:
Bean依賴容器:也就是說Bean要依賴於容器,這里的依賴是指容器負責創建Bean並管理Bean的生命周期,正是由於由容器來控制創建Bean並注入依賴,也就是控制權被反轉了,這也正是IoC名字的由來,此處的有依賴是指Bean和容器之間的依賴關系。
容器注入Bean的依賴資源:容器負責注入Bean的依賴資源,依賴資源可以是Bean、外部文件、常量數據等,在Java中都反映為對象,並且由容器負責組裝Bean之間的依賴關系,此處的依賴是指Bean之間的依賴關系,可以認為是傳統類與類之間的“關聯”、“聚合”、“組合”關系。
理解DI的關鍵是:“誰依賴誰,為什么需要依賴,誰注入誰,注入了什么”,那我們來深入分析一下:
誰依賴於誰:當然是應用程序依賴於IoC容器;
為什么需要依賴:應用程序需要IoC容器來提供對象需要的外部資源;
誰注入誰:很明顯是IoC容器注入應用程序某個對象,應用程序依賴的對象;
注入了什么:就是注入某個對象所需要的外部資源(包括對象、資源、常量數據)。
為什么要應用依賴注入,應用依賴注入能給我們帶來哪些好處呢?
動態替換Bean依賴對象,程序更靈活:替換Bean依賴對象,無需修改源文件:應用依賴注入后,由於可以采用配置文件方式實現,從而能隨時動態的替換Bean的依賴對象,無需修改java源文件;
更好實踐面向接口編程,代碼更清晰:在Bean中只需指定依賴對象的接口,接口定義依賴對象完成的功能,通過容器注入依賴實現;
更好實踐優先使用對象組合,而不是類繼承:因為IoC容器采用注入依賴,也就是組合對象,從而更好的實踐對象組合。
采用對象組合,Bean的功能可能由幾個依賴Bean的功能組合而成,其Bean本身可能只提供少許功能或根本無任何功能,全部委托給依賴Bean,對象組合具有動態性,能更方便的替換掉依賴Bean,從而改變Bean功能;
而如果采用類繼承,Bean沒有依賴Bean,而是采用繼承方式添加新功能,,而且功能是在編譯時就確定了,不具有動態性,而且采用類繼承導致Bean與子Bean之間高度耦合,難以復用。
增加Bean可復用性:依賴於對象組合,Bean更可復用且復用更簡單;
降低Bean之間耦合:由於我們完全采用面向接口編程,在代碼中沒有直接引用Bean依賴實現,全部引用接口,而且不會出現顯示的創建依賴對象代碼,而且這些依賴是由容器來注入,很容易替換依賴實現類,從而降低Bean與依賴之間耦合;
代碼結構更清晰:要應用依賴注入,代碼結構要按照規約方式進行書寫,從而更好的應用一些最佳實踐,因此代碼結構更清晰。
從以上我們可以看出,其實依賴注入只是一種裝配對象的手段,設計的類結構才是基礎,如果設計的類結構不支持依賴注入,Spring IoC容器也注入不了任何東西,從而從根本上說“如何設計好類結構才是關鍵,依賴注入只是一種裝配對象手段”。
IoC 和 DI 有什么關系呢?其實它們是同一個概念的不同角度描述,由於控制反轉概念比較含糊(可能只是理解為容器控制對象這一個層面,很難讓人想到誰來維護對象關系),所以2004年大師級人物Martin Fowler又給出了一個新的名字:“依賴注入”。相對IoC 而言,“依賴注入”明確描述了“被注入對象依賴IoC容器配置依賴對象”。
注:如果想要更加深入的了解IoC和DI,請參考大師級人物Martin Fowler的一篇經典文章《Inversion of Control Containers and the Dependency Injection pattern》,原文地址:http://www.martinfowler.com/articles/injection.html。
1.4 IoC容器的概念
IoC容器就是具有依賴注入功能的容器,IoC容器負責實例化、定位、配置應用程序中的對象及建立這些對象間的依賴。應用程序無需直接在代碼中new相關的對象,應用程序由IoC容器進行組裝。在Spring中BeanFactory是IoC容器的實際代表者。
Spring IoC容器如何知道哪些是它管理的對象呢?這就需要配置文件,Spring IoC容器通過讀取配置文件中的配置元數據,通過元數據對應用中的各個對象進行實例化及裝配。一般使用基於xml配置文件進行配置元數據,而且Spring與配置文件完全解耦的,可以使用其他任何可能的方式進行配置元數據,比如注解、基於java文件的、基於屬性文件的配置都可以。
那Spring IoC容器管理的對象叫什么呢?
2.1 Bean的概念
由IoC容器管理的那些組成你應用程序的對象我們就叫它Bean, Bean就是由Spring容器初始化、裝配及管理的對象,除此之外,bean就與應用程序中的其他對象沒有什么區別了。那IoC怎樣確定如何實例化Bean、管理Bean之間的依賴關系以及管理Bean呢?這就需要配置元數據,在Spring中由BeanDefinition代表,配置元數據指定如何實例化Bean、如何組裝Bean等。
讓我們來看下IoC容器到底是如何工作。在此我們以xml配置方式來分析一下:
① 准備配置文件:就像前邊Hello World配置文件一樣,在配置文件中聲明Bean定義也就是為Bean配置元數據。
② 由 IoC容器進行解析元數據: IoC容器的Bean Reader讀取並解析配置文件,根據定義生成BeanDefinition配置元數據對象,IoC容器根據BeanDefinition進行實例化、配置及組裝Bean。
③ 實例化 IoC容器:由客戶端實例化容器,獲取需要的Bean。
執行過程如下圖:
2.2 實例化Bean
Spring IoC容器如何實例化Bean呢?傳統應用程序可以通過new和反射方式進行實例化Bean。而Spring IoC容器則需要根據Bean定義里的配置元數據使用反射機制來創建Bean。在Spring IoC容器中根據Bean定義創建Bean主要有以下幾種方式:
1、使用構造器實例化Bean:這是最簡單的方式,Spring IoC容器既能使用默認空構造器也能使用有參數構造器兩種方式創建Bean,如以下方式指定要創建的Bean類型:
① 使用空構造器進行定義,使用此種方式,class屬性指定的類必須有空構造器
1 <bean name="bean1" class="cn.javass.spring.chapter2.HelloImpl2"/>
② 使用有參數構造器進行定義,使用此種方式,可以使用< constructor-arg >標簽指定構造器參數值,其中index表示位置,value表示常量值,也可以指定引用,指定引用使用ref來引用另一個Bean定義:
1 <bean name="bean2" class="cn.javass.spring.chapter2.HelloImpl2"> 2 <!-- 指定構造器參數 --> 3 <constructor-arg index="0" value="Hello Spring!"/> 4 </bean>
2、使用靜態工廠方式實例化Bean,使用這種方式除了指定必須的class屬性,還要指定factory-method屬性來指定實例化Bean的方法,而且使用靜態工廠方法也允許指定方法參數,spring IoC容器將調用此屬性指定的方法來獲取Bean,配置如下所示:
① 先來看看靜態工廠類代碼吧HelloApiStaticFactory:
1 public class HelloApiStaticFactory { 2 //工廠方法 3 public static HelloApi newInstance(String message) { 4 //返回需要的Bean實例 5 return new HelloImpl2(message); 6 } 7 }
② 靜態工廠寫完了,讓我們在配置文件(resources/chapter2/instantiatingBean.xml)配置Bean定義:
1 <!-- 使用靜態工廠方法 --> 2 <bean id="bean3" class="cn.javass.spring.chapter2.HelloApiStaticFactory" factory-method="newInstance"> 3 <constructor-arg index="0" value="Hello Spring!"/> 4 </bean>
3、使用實例工廠方法實例化Bean,使用這種方式不能指定class屬性,此時必須使用factory-bean屬性來指定工廠Bean,factory-method屬性指定實例化Bean的方法,而且使用實例工廠方法允許指定方法參數,方式和使用構造器方式一樣,配置如下:
① 實例工廠類代碼(HelloApiInstanceFactory.java)如下:
1 public class HelloApiInstanceFactory { 2 public HelloApi newInstance(String message) { 3 return new HelloImpl2(message); 4 } 5 }
② 在配置文件(resources/chapter2/instantiatingBean.xml)配置Bean定義:
1 <!—1、定義實例工廠Bean --> 2 <bean id="beanInstanceFactory" class="cn.javass.spring.chapter2.HelloApiInstanceFactory"/> 3 <!—2、使用實例工廠Bean創建Bean --> 4 <bean id="bean4" factory-bean="beanInstanceFactory"factory-method="newInstance"> 5 <constructor-arg index="0" value="Hello Spring!"></constructor-arg> 6 </bean>
通過以上例子我們已經基本掌握了如何實例化Bean了,大家是否注意到?這三種方式只是配置不一樣,從獲取方式看完全一樣,沒有任何不同。這也是Spring IoC的魅力,Spring IoC幫我們創建Bean,我們只管使用就可以了。
3 AOP
4 總結
1. Ioc和DI其實是一種思想,並不是具體的技術,當我們在搭建SSM項目的時候就是用到了這種思想。
2. 首先Spring是個大容器,可以把整個項目都包含進去,而Ioc和DI就是運轉整個項目的核心思想。
3. 項目的運行和周期由Ioc控制,事件的請求和反應由DI控制
4. 就比如:org.springframework.web.servlet.DispatcherServlet前端配置類,當前端發出請求后,Ioc會控制這個請求的接收,通過spring中的類來找到controller,而不是用戶自己去接收前端請求,這就是Ioc的一個應用
比如就是有一個商場類,人類要去買東西,有了依賴注入后,我們就不需要New一個商場類、人類、和具體商品類,我們只需要在配置中配好,然后調用具體的購買方法,傳入想買的物品類,就可以通過同期得到想要的結果了,說白了,就是讓你少New了幾個類,但是在大項目中就可以節省程序員很多精力,更加專注的開發具體邏輯。
詳情例子:http://blog.csdn.net/u014563989/article/details/55188673
5. DI(依賴注入)的思想可以在創建數據庫連接上體現,整個項目穿件連接時並不是當需要連接時new一個連接,而是項目在配置的時候創建好連接,當要用的時候,DI會給程序去用,而程序在什么時候用和怎么用時開發者不知道的,但最后還是實現了功能。
本文部分內容轉自:http://jinnianshilongnian.iteye.com/blog/1413846