1. 程式人生 > >詳談 Spring 中的 IOC 和 AOP

詳談 Spring 中的 IOC 和 AOP

這篇文章主要講 Spring 中的幾個點,Spring 中的 IOC,AOP,下一篇說說 Spring 中的事務操作,註解和 XML 配置。

 

Spring 簡介

Spring 是一個開源的輕量級的企業級框架,其核心是反轉控制 (IoC) 和麵向切面 (AOP) 的容器框架。我們可以把 Spring 看成是物件的容器,容器中可以包含很多物件,所以 Spring 有很多強大的功能。

 

一句話,Spring 是專案中物件的管家,負責管理專案中用到的所有物件。所以在專案三層架構中,Spring 不屬於某一特定層。

 

Spring 的 Hello World

想要構建一個 Spring 的入門程式,我們需要匯入 4 個核心包和 2 個輔助包,建立一個實體類,最主要的是編寫核心配置檔案,applicationContext.xml 放在 src 下。最後寫一個測試類即可。此時在測試類中我們不需要在使用 new 關鍵字去建立物件了。這也正是 Spring 的作用所在,會自動給我建立物件。

 

上圖展示的就是最基本的演示,也是很容易就理解了,配置檔案中配置了 user 物件,我們通過載入配置檔案來獲取物件從而避免了使用 new 來建立。

 

什麼是 IOC

到這裡我們就可以解釋一下 Spring 中的核心概念之一的 IOC,即 inverse of control ,翻譯過來就是反轉控制。想想我們以前想要一個物件就會主動的 new 。現在 Spring 會幫我們建立物件,不需要手工 new(但是要記得配置呀)反轉說的就是建立物件的方式反轉了,以前是我們自己建立物件,現在由 Spring 為我們建立。

 

控制又是指什麼呢?一個物件要有屬性值吧,還有可能存在其它的物件,控制說的就是這些屬性和引用不需要自己寫了,由 Spring 來為我們自動建立(其實還是我們自己配置的~)。

 

總結下來就是 Spring 可以自動的為我們建立物件,並注入依賴。而反轉控制說的就是以前我們自己建立物件和依賴,現在由程式為我們建立。

 

Spring 建立物件的方式

那 Spring 又是如何為我們建立的呢?我們知道物件的建立必須要經過構造器,從上面的例子中看到,我們只配置了一個<bean>標籤,其實這就是將空參構造器使用配置檔案給表示出來罷了。Spring 中建立物件也就是這麼簡單,當然配置可以更復雜些,後面再說,但目前我們可以知道,Spring 建立物件的就是通過配置 bean 標籤,呼叫構造器來實現的。如何呼叫構造器的,那肯定是反射搞的鬼。

 

藏在 IOC 背後的 DI

DI,Dependency Injection,即依賴注入。IOC 還體現在自動注入依賴,依賴注入這詞聽起來不太明白,簡單的理解為繫結資料,這是一種具體的技術,IOC 是思想,DI 是技術實現。物件之中需要其它的物件,類如 Service 層中需要 DAO 層物件,我們不需要在 Service 中手動 new 了,只需要配置一下即可。

 

常用的注入方式有兩種,set 方法注入和構造方法注入。而每一種注入方式中又有注入基本資料型別和引用資料型別之分。下面就看看如何配置。

 

set 方法注入

 

 

通過 property 標籤來配置屬性,基本資料型別使用 value 屬性即可,若是引用型別則使用 ref 。注意,User 物件中要有 Car 引用並且提供其 set 方法。

 

構造方法注入

 

 

這個配置看一眼就基本理解了,非常簡單,說個小細節,物件的建立需要執行構造器,我們在初始化物件的時候會使用反射通過全類名得到物件,而這時就需要一個空參的構造器,我們不提供構造器的情況下,程式會自動為我們提供一個空參構造器,但是一旦重寫構造器,我們就需要提供空參構造器,不然就報錯。

 

雖然還有其它屬性注入的方式,比方說 p 名稱空間注入,spel 注入,但是這些都不重要!最常用的就一個那就是 set 方法注入。抓住重點,簡單省時。

 

總結一下,以上主要說了什麼是 Spring,如何搭建入門專案,解釋了 IOC 思想,以及站在 IOC 背後的技術 DI,我們使用 set 方式注入基本資料型別和引用資料型別,當然,這些東西都構建在反射之上。

 

AOP 介紹

AOP 是我們經常聽到的概念,然而聽的太多我們卻忘記了最初的定義,全稱 Aspect Oriented Programming 翻譯過來就是面向切面程式設計。首先,要搞清楚這是一種思想,Spring 的核心思想就有 AOP 。

 

嘗試理解一下 AOP 的思想,簡單來說就是“縱向重複,橫向抽取”這很抽象,舉幾個例子,Filter 的思想,過濾器在解決亂碼的時候不需要我們在每一個類中都寫處理亂碼的程式碼。而是直接由 Fliter 來統一處理。還有攔截器的思想,我們在 Action 中需要對引數進行校驗、封裝,而攔截器又是統一對引數進行校驗、封裝。

 

不管是 Fliter 還是攔截器,都是面向切面程式設計思想的具體應用。而我們今天說的 Spring 中的 AOP 又是如何體現呢?

 

動態代理和 cglib 代理

那就是通過代理,Spring 中通過代理達到統一增強代理物件的目的,而不需要對類中的方法一個一個增強。我們以前接觸過動態代理,知道在動態代理中我們的代理物件和被代理物件需要實現同一個介面,在 Spring 中無法保證每個需要增強的類都實現介面,所以就需要引用另外一種代理技術 cglib 代理。

 

總結一下就是 Spring 中通過代理來體現 AOP 的思想,而代理的實現又分為動態代理和 cglib 代理。動態代理要求代理類和被代理類實現同一個介面。而 cglib 是繼承代理,代理物件只需繼承被代理物件即可實現。在 Spring 中優先使用動態代理。

 

兩種代理方式有不同的測試程式碼,這裡我不再展示,當我敲程式碼的時候我突然想到來上海第一次面試的時候,面試官就讓我實現一下 Spring 中的 AOP,現在終於想通了,就是讓我寫一下兩種代理方法的實現呀。可惜,當時一臉懵逼……

 

Spring 中與 AOP 相關名詞

連線點(joinPoint): 在目標物件中,所有可以增強的方法。

切入點(pointCut): 在目標物件中,已經增強的方法。

增強/通知(advice): 增強的程式碼。

目標物件(target): 被代理物件。

織入(weaving): 將通知應用到到連線點。

代理(Proxy): 將通知織入到目標物件形成代理物件。

切面(aspect): 切入點+通知。

 

下面通過程式碼展示一下 Spring 中 AOP 的展示,順帶看看與這幾個名詞的物件關係。

 

 

上面的整個過程就是 Spring 中 AOP 的體現,將通知織入到目標物件中形成代理的這麼一個過程。我們為了這個需要準備目標物件,通知物件,還要學會如何配置切點和切面。

 

上面只是為了測試一下能否正確的生成代理物件,而在 Spring 中真正應用 AOP 的是對事務的處理。Spring AOP 實質就是幫我們生成代理物件,而這個代理物件包含了對事務的處理。我們通過配置即可生成代理物件,而不需要我們再手敲程式碼處理事務。

 

在 Spring 中還提供了使用註解來配置,註釋的出現就是為了替換配置檔案,然而註釋使用的不多。

 

總結一下,IoC 和 AOP 都是 Spring 中的核心概念,IoC 體現在 Spring 會為我們自動建立物件,由以前的手動 new 物件,到現在 Spring 統一管理。

 

我想到一個例子來說明一下 AOP,高速路上的收費站就是一個切面,Spring 的 IoC 就是一個發車站,負責維護汽車物件和依賴物件汽車上的人,車就是目標物件,而我們要生成的代理物件就是通過收費站的汽車。