SSM框架中IoC、DI與AOP的理解


  框架封裝了普通項目中程序員需要重復書寫的代碼和調用過程,就比如說在傳統的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容器也注入不了任何東西,從而從根本上說“如何設計好類結構才是關鍵,依賴注入只是一種裝配對象手段”。

 

  IoCDI 有什么關系呢?其實它們是同一個概念的不同角度描述,由於控制反轉概念比較含糊(可能只是理解為容器控制對象這一個層面,很難讓人想到誰來維護對象關系),所以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

  面向切面編程(AOP)提供另外一種角度來思考程序結構,通過這種方式彌補了面向對象編程(OOP)的不足。
  除了類(classes)以外,AOP提供了切面。切面對關注點進行模塊化,例如橫切多個類型和對象的事務管理。Spring的一個關鍵的組件就是AOP框架,可以自由選擇是否使用AOP。
  提供聲明式企業服務,特別是為了替代EJB聲明式服務。最重要的服務是聲明性事務管理,這個服務建立在Spring的抽象事物管理之上。
  允許用戶實現自定義切面,用AOP來完善OOP的使用可以把Spring AOP看作是對Spring的一種增強。

 

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM