?上一篇:

Spring核心技術原理-(1)-通過Web開發演進過程了解一下為什麼要有Spring?

上一篇從Web開發演進過程的一個側面簡述了一下為什麼會有Spring?事實上只介紹了為什麼會有Spring IOC(控制反轉/依賴注入)以及Spring IOC的雛形。我們都知道Spring的兩個核心知識點是:IOC和AOP。因此,這一篇還是以Web開發演進過程為線索繼續探討一下為什麼會有Spring AOP?等介紹完這兩個核心的知識點之後,才會進一步展開對Spring核心原理的探討!

一、Web開發演進到一定階段的痛點

我們在初學習Java Web的時候,應該都經歷了以下的階段:

(1)一個主函數main中包含了所有的方法; (2)將主函數中的方法進行拆分封裝,抽取為一個個的方法; (3)按照每一個方法不同的功能分為一個個的類; (4)有了MVC模型之後,我們按照MVC的思想將我們的代碼拆分為三層,每層負責不同的功能,進行分門別類的管理;

很多程序的功能還可以通過繼承關係而得到重用,進一步提高了開發效率。再後來,又出現了各種各樣的設計模式,使設計程序功能變得得心應手。

在面向對象的大環境下,我們可以很好地組織代碼,通過繼承、封裝和多態的思想去設計一個個比較讓人滿意的類,但是我們慢慢的發現,我們的代碼中逐漸多了很多重複性的代碼,有人可能會想到,把這些重複性的代碼抽取出來不就好了嗎?是這樣的,我們看一下這種思路的一個實例:

可以看到,上述代碼功能上確實可以實現,但是我們的業務代碼已經被這些非核心的代碼所混淆,並且佔據了大量的空間!顯然這種顯示的調用過程成為了我們開發過程中的一個痛點,如何將類似這種的非核心的代碼剝離出去成為一個迫切需要解決的問題!

不僅如此,假設我們要控制每一個方法的訪問許可權,只允許一部分用戶進行訪問,在不考慮過濾器的情況下,我們是不是需要在每一個方法開始的時候判斷用戶是否具有該許可權,如果有的話就可以進行訪問,如果沒有的話,就不允許進行訪問!

諸如此類,還有資料庫事務的控制,資料庫連接的創建和關閉等等,這些都充斥這大量重複性的模板代碼!一個很現實的問題,假如有一天,業務需求不需要進行日誌記錄了,那豈不是我們需要把以前寫的代碼,全部刪掉!想想都是一件很可怕的事情!

二、使用設計模式進行一次改進

如果你對設計模式玩的比較熟的話,這個時候你可能會想到使用JDK動態代理設計模式(動態代理設計模式可以在原有的方法前後添加判斷、選擇或其他邏輯)對上述代碼進行改進,(關於什麼是JDK動態代理,這裡不再詳細贅述,有不懂的的可以查閱相關資料具體了解一下!)修改後的代碼如下:

上述為代理類,紅色框中圈出的表示以前業務中的模板代碼,這裡直接輸出表示方法執行的過程,以前的UserServiceImpl修改為如下(直接用輸出的方式表示方法執行了):

測試代碼如下:

上述的執行結果可以看出,每次調用一個方法的時候前後都會調用我們期望的代碼,實現了我們期望的標準!

通過JDK動態代理的方式,讓我們徹底的解放出來了!

三、撕開披在AOP身上的一層薄紗

上述過程中,我們看到在動態代理的invoke方法裡邊,我們相當於在原有方法的調用前後「植入」了我們的通用日誌記錄代碼,如果你看到這一層的話,那麼恭喜你!你已經領悟到了AOP思想最核心的東西了!上述抽取公共代碼其實就是AOP中橫切的過程,代理對象中在方法調用前後「植入」自己寫的通用日誌記錄代碼其實就是AOP中織入的過程!這個織入的代碼也就是橫切邏輯,織入代碼的過程其實就是在原有的方法前後增強 原方法的過程!總的來說,我們想解決我們開發中的痛點,然後就出現了一種技術,這種技術手段就是AOP。

AOP書面表述如下:

AOP(Aspect Oriented Programming)意為:面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容(Spring核心之一),是函數式編程的一種衍生范型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。

四、AOP與Spring AOP的關係

AOP是一種思想,不同的廠商或企業可能有不同的實現方式,為了更好的應用AOP技術,技術專家們成立了AOP聯盟來探討AOP的標準化,AOP聯盟定義的AOP體系結構把與AOP相關的概念大致分為由高到低、從使用到實現的三層關係,AOP聯盟定義的AOP體系結構如下圖:

在AOP聯盟定義的AOP體系結構下有很多的實現者,例如:AspectJ、AspectWerkz、JBoss AOP、Spring AOP等。Spring AOP就是在此標準下產生的,這裡不再深入Spring AOP的其他概念,這些概念會在後期探討。

五、其他問題

上述通過動態代理的方式實現了簡單的AOP,但是值得注意的是,我們的代理目標對象必須實現一個介面,要是一個介面的實現類,這是因為再生成Proxy對象的時候這個方法需要一個目標對象的介面:

顯然,這種特殊的場景使用JDK動態代理的技術已經不能夠滿足我們的使用場景了,又遇到痛點了!凡事不勞我們操心的Spring框架已經替我們想到了,既然你有這種需求,我就使用一種技術幫你實現就行了,Spring在這裡使用CGLib的代理方式實現了我們的這種訴求。

CGLib採用底層的位元組碼技術,可以為一個類創建子類,在子類中採用方法攔截的技術攔截所有父類方法的調用並順勢的織入橫切邏輯。

看到這裡,我們會想以後會不會還有CGLib解決不了得問題啊?我們已經很清楚的知道了對於Spring AOP來說,使用到了JDK動態代理技術和CGLib動態代理技術,這兩種方式已經實現了我們絕大多數的場景,如果還有不能滿足的需求,迫切需要解決的痛點,我相信可能還會有相應的技術實現AOP。

六、總結

上述的過程,大致從一個側面探討了一下我們為什麼需要AOP,AOP與Spring AOP的關係以及Spring AOP兩種實現的方式(JDK動態代理和CGLib動態代理)。

Spring不嘗試提供最為完善的AOP實現,它更側重於提供一種和Spring IOC容器整個的AOP實現,用於解決實際的問題,在Spring中無縫的整合了Spring AOP、Spring IOC和AspectJ。

當然,Spring AOP的內容不僅僅有這些!例如:我們在使用Spring AOP的時候只是簡單的配置了一下(通過XML或註解進行配置),沒有像ProxyDemo測試類中的那樣,還需要我們手動的調用ProxyFactory 來創建代理對象,然後調用我們的目標方法,其實Spring AOP在內部已經幫我們把這些事情做好了,具體的原理後期會繼續探討。另外,Spring如何整合Spring IOC和AOP的,這一點也會在後期探討。

最後補充一下!動態代理或者設計模式重要嗎?很重要!Spring AOP用到了動態代理,Spring事務管理用到了動態代理,MyBatis資料庫連接池用到了動態代理,MyBatis創建Mapper用到了動態代理等等,你說重要不!要想踏進這些高層框架原理的大門,設計模式首先是我們的第一段台階!


搜索或掃描下述二維碼關注微信公眾號:Java後端技術(ID: JavaITWork),和20萬人一起學Java!

Java後端技術專註Java相關技術:SSM、Spring全家桶、微服務、MySQL、MyCat、集群、分散式、中間件、Linux、網路、多線程,偶爾講點運維Jenkins、Nexus、Docker、ELK,偶爾分享些技術乾貨,致力於Java全棧開發!


推薦閱讀:
相关文章