Java Web (一) Spring基礎之AOP
1.AOP的作用
在OOP中,正是這種分散在各處且與物件核心功能無關的程式碼(橫切程式碼)的存在,使得模組複用難度增加。AOP則將封裝好的物件剖開,找出其中對多個物件產生影響的公共行為,並將其封裝為一個可重用的模組,這個模組被命名為“切面”(Aspect),切面將那些與業務無關,卻被業務模組共同呼叫的邏輯提取並封裝起來,減少了系統中的重複程式碼,降低了模組間的耦合度,同時提高了系統的可維護性。
將被多個模組呼叫的公共行為,封裝成為一個可重用的模組(模組,可能只是一個類,或者是一個jar包),減少系統中的重複程式碼,降低模組間的耦合,提高系統可維護性
2.DI 和 IOC 概念
依賴注入或控制反轉的定義中,呼叫者不負責被呼叫者的例項建立工作,該工作由Spring框架中的容器來負責,它通過開發者的配置來判斷例項型別,建立後再注入呼叫者。由於Spring容器負責被呼叫者例項,例項建立後又負責將該例項注入呼叫者,因此稱為依賴注入。而被呼叫者的例項建立工作不再由呼叫者來建立而是由Spring來建立,控制權由應用程式碼轉移到了外部容器,控制權發生了反轉,因此稱為控制反轉。
3.BeanFactory與ApplicationContext
ApplicationContext是BeanFactory的子介面,也被稱為應用上下文。BeanFactory提供了Spring的配置框架和基本功能,ApplicationContext則添加了更多企業級功能(如國際化的支援),他另一重要優勢在於當ApplicationContext容器初始化完成後,容器中所有的 singleton Bean 也都被例項化了,也就是說當你需要使用singleton Bean 是,在應用中無需等待就可以用,而其他BeanFactory介面的實現類,則會延遲到呼叫 getBean()方法時構造,ApplicationContext的初始化時間會稍長些,呼叫getBean()是由於Bean已經構造完畢,速度會更快。因此大部分系統都使用ApplicationContext,而只在資源較少的情況下,才考慮使用BeanFactory。
4.AOP的實現策略
(1)Java SE動態代理: 使用動態代理可以為一個或多個介面在執行期動態生成實現物件,生成的物件中實現介面的方法時可以新增增強程式碼,從而實現AOP。缺點是隻能針對介面進行代理,另外由於動態代理是通過反射實現的,有時可能要考慮反射呼叫的開銷。 (2)位元組碼生成(CGLib 動態代理) 動態位元組碼生成技術是指在執行時動態生成指定類的一個子類物件,並覆蓋其中特定方法,覆蓋方法時可以新增增強程式碼,從而實現AOP。其常用工具是cglib。 (3)定製的類載入器 當需要對類的所有物件都新增增強,動態代理和位元組碼生成本質上都需要動態構造代理物件,即最終被增強的物件是由AOP框架生成,不是開發者new出來的。解決的辦法就是實現自定義的類載入器,在一個類被載入時對其進行增強。JBoss就是採用這種方式實現AOP功能。 (4)程式碼生成 利用工具在已有程式碼基礎上生成新的程式碼,其中可以新增任何橫切程式碼來實現AOP。 (5)語言擴充套件 可以對構造方法和屬性的賦值操作進行增強,AspectJ是採用這種方式實現AOP的一個常見Java語言擴充套件。 AOP把軟體系統分為兩個部分:核心關注點和橫切關注點。 業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處基本相似,比如許可權認證、日誌、事物。AOP的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。 AOP程式設計其實是很簡單的事情,縱觀AOP程式設計,程式設計師只需要參與三個部分: 1、定義普通業務元件 --業務實現 2、定義切入點pointcut,一個切入點可能橫切多個業務元件 3、定義增強處理,增強處理就是在AOP框架為普通業務元件織入的處理動作 對指定pointcut定義增強處理 如:@Before(“logPointCut()”) 即@Before("pointcut方法") 所以進行AOP程式設計的關鍵就是定義切入點和定義增強處理,一旦定義了合適的切入點和增強處理,AOP框架將自動生成AOP代理,即:代理物件的方法=增強處理+被代理物件的方法。 aop相當於對動態代理的封裝 常用: @Order ,Join point???
AOP
AOP(Aspect Oriented Programming),即面向切面程式設計,可以說是OOP(Object Oriented Programming,面向物件程式設計)的補充和完善。OOP引入封裝、繼承、多型等概念來建立一種物件層次結構,用於模擬公共行為的一個集合。不過OOP允許開發者定義縱向的關係,但並不適合定義橫向的關係,例如日誌功能。日誌程式碼往往橫向地散佈在所有物件層次中,而與它對應的物件的核心功能毫無關係對於其他型別的程式碼,如安全性、異常處理和透明的持續性也都是如此,這種散佈在各處的無關的程式碼被稱為橫切(cross cutting),在OOP設計中,它導致了大量程式碼的重複,而不利於各個模組的重用。
AOP技術恰恰相反,它利用一種稱為"橫切"的技術,剖解開封裝的物件內部,並將那些影響了多個類的公共行為封裝到一個可重用模組,並將其命名為"Aspect",即切面。所謂"切面",簡單說就是那些與業務無關,卻為業務模組所共同呼叫的邏輯或責任封裝起來,便於減少系統的重複程式碼,降低模組之間的耦合度,並有利於未來的可操作性和可維護性。
使用"橫切"技術,AOP把軟體系統分為兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處基本相似,比如許可權認證、日誌、事物。AOP的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。
AOP核心概念
1、橫切關注點
對哪些方法進行攔截,攔截後怎麼處理,這些關注點稱之為橫切關注點
2、切面(aspect)
類是對物體特徵的抽象,切面就是對橫切關注點的抽象
3、連線點(joinpoint)
被攔截到的點,因為Spring只支援方法型別的連線點,所以在Spring中連線點指的就是被攔截到的方法,實際上連線點還可以是欄位或者構造器
4、切入點(pointcut)
對連線點進行攔截的定義
5、通知(advice)
所謂通知指的就是指攔截到連線點之後要執行的程式碼,通知分為前置、後置、異常、最終、環繞通知五類
6、目標物件
代理的目標物件
7、織入(weave)
將切面應用到目標物件並導致代理物件建立的過程
8、引入(introduction)
在不修改程式碼的前提下,引入可以在執行期為類動態地新增一些方法或欄位
Spring對AOP的支援
Spring中AOP代理由Spring的IOC容器負責生成、管理,其依賴關係也由IOC容器負責管理。因此,AOP代理可以直接使用容器中的其它bean例項作為目標,這種關係可由IOC容器的依賴注入提供。Spring建立代理的規則為:
1、預設使用Java動態代理來建立AOP代理,這樣就可以為任何介面例項建立代理了
2、當需要代理的類不是代理介面的時候,Spring會切換為使用CGLIB代理,也可強制使用CGLIB
AOP程式設計其實是很簡單的事情,縱觀AOP程式設計,程式設計師只需要參與三個部分:
1、定義普通業務元件 --業務實現
2、定義切入點pointcut,一個切入點可能橫切多個業務元件
3、定義增強處理,增強處理就是在AOP框架為普通業務元件織入的處理動作 對指定pointcut定義增強處理
所以進行AOP程式設計的關鍵就是定義切入點和定義增強處理,一旦定義了合適的切入點和增強處理,AOP框架將自動生成AOP代理,即:代理物件的方法=增強處理+被代理物件的方法。
AOP就是面向切面程式設計,我們可以從以下幾個層面來實現AOP
在編譯期修改原始碼
在執行期位元組碼載入前修改位元組碼
在執行期位元組碼載入後動態建立代理類的位元組碼
2、AOP各種實現機制的比較
以下是各種實現機制的比較:
類別 機制 原理 優點 缺點
靜態AOP 靜態織入 在編譯期,切面直接以位元組碼的形式編譯到目標位元組碼檔案中 對系統無效能影響 靈活性不夠
動態AOP 動態代理 在執行期,目標類載入後,為介面動態生成代理類,將切面織入到代理類中 相對於靜態AOP更加靈活 切入的關注點需要實現介面。
對系統有一點效能影響
動態位元組碼生成 CGLIB 在執行期,目標類載入後,動態構建位元組碼檔案生成目標類的子類,將切面邏輯加入到子類中 沒有介面也可以織入 擴充套件類的例項方法為final時,則無法進行織入
自定義類載入器 在執行期,目標載入前,將切面邏輯加到目標位元組碼裡 可以對絕大部分類進行織入 程式碼中如果使用了其他類載入器,則這些類將不會被織入
位元組碼轉換 在執行期,所有類載入器載入位元組碼前進行攔截 可以對所有類進行織入
應用
事務
快取
攔截器
註解
AOP功能
效能監控:在方法呼叫前後記錄呼叫時間,方法執行太長或超時報警
快取代理:快取某方法的返回值,下次執行該方法時,直接從快取裡獲取
軟體破解:使用AOP修改軟體的驗證類的判斷邏輯
記錄日誌:在方法執行前後記錄系統日誌
工作流系統:工作流系統需要將業務程式碼和流程引擎程式碼混合在一起執行,那麼我們可以使用AOP將其分離,並動態掛接業務
許可權驗證:方法執行前驗證是否有許可權執行當前方法,沒有則丟擲沒有許可權執行異常,由業務程式碼捕捉
OOP使用過程中,遇到的問題,發展而來的
分散在各處且與物件核心功能無關的程式碼(橫切程式碼)的存在,使得模組複用難度增加。這個時候,AOP就產生了
AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函數語言程式設計的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
從AOP的角度看,所謂“橫切關注點”就是那些在職責上是內聚的,但在使用上又會散佈在所有物件層次中,且與所散佈到的物件的核心功能毫無關係的關注點。與“橫切關注點”對應的是“核心關注點”,就是與系統業務有關的領域邏輯。例如訂單業務是核心關注點,插入訂單時的事務管理則是橫切關注點。
橫切關注點與核心關注點是分離的,因此與具體的業務無關。於是,我們可以得到應用服務設計的第一條原則:與橫切關注點協作的服務應被定義為應用服務。(DDD)
AOP存在的價值
在傳統 OOP 程式設計裡以物件為核心,整個軟體系統由系列相互依賴的物件所組成,而這些物件將被抽象成一個一個的類,並允許使用類繼承來管理類與類之間一般到特殊的關係。隨著軟體規模的增大,應用的逐漸升級,慢慢出現了一些 OOP 很難解決的問題。
我們可以通過分析、抽象出一系列具有一定屬性與行為的物件,並通過這些物件之間的協作來形成一個完整的軟體功能。由於物件可以繼承,因此我們可以把具有相同功能或相同特性的屬性抽象到一個層次分明的類結構體系中。隨著軟體規範的不斷擴大,專業化分工越來越系列,以及 OOP 應用實踐的不斷增多,隨之也暴露出了一些 OOP 無法很好解決的問題。
現在假設系統中有 3 段完全相似的程式碼,這些程式碼通常會採用“複製”、“貼上”方式來完成,通過這種“複製”、“貼上”方式開發出來的軟體如圖 1 所示。
圖 1.多個地方包含相同程式碼的軟體
看到如圖 1 所示的示意圖,可能有的讀者已經發現了這種做法的不足之處:如果有一天,圖 1 中的深色程式碼段需要修改,那是不是要開啟 3 個地方的程式碼進行修改?如果不是 3 個地方包含這段程式碼,而是 100 個地方,甚至是 1000 個地方包含這段程式碼段,那會是什麼後果?
為了解決這個問題,我們通常會採用將如圖 1 所示的深色程式碼部分定義成一個方法,然後在 3 個程式碼段中分別呼叫該方法即可。在這種方式下,軟體系統的結構如圖 2 所示。
圖 2 通過方法呼叫實現系統功能
對於如圖 2 所示的軟體系統,如果需要修改深色部分的程式碼,只要修改一個地方即可,不管整個系統中有多少地方呼叫了該方法,程式無須修改這些地方,只需修改被呼叫的方法即可——通過這種方式,大大降低了軟體後期維護的複雜度。
對於如圖 2 所示的方法 1、方法 2、方法 3 依然需要顯式呼叫深色方法,這樣做能夠解決大部分應用場景。但對於一些更特殊的情況:應用需要方法 1、方法 2、方法 3 徹底與深色方法分離——方法 1、方法 2、方法 3 無須直接呼叫深色方法,那如何解決?
因為軟體系統需求變更是很頻繁的事情,系統前期設計方法 1、方法 2、方法 3 時只實現了核心業務功能,過了一段時間,我們需要為方法 1、方法 2、方法 3 都增加事務控制;又過了一段時間,客戶提出方法 1、方法 2、方法 3 需要進行使用者合法性驗證,只有合法的使用者才能執行這些方法;又過了一段時間,客戶又提出方法 1、方法 2、方法 3 應該增加日誌記錄;又過了一段時間,客戶又提出……面對這樣的情況,我們怎麼辦?通常有兩種做法:
•
根據需求說明書,直接拒絕客戶要求。
•
擁抱需求,滿足客戶的需求。
第一種做法顯然不好,客戶是上帝,我們應該儘量滿足客戶的需求。通常會採用第二種做法,那如何解決呢?是不是每次先定義一個新方法,然後修改方法 1、方法 2、方法 3,增加呼叫新方法?這樣做的工作量也不小啊!我們希望有一種特殊的方法:我們只要定義該方法,無須在方法 1、方法 2、方法 3 中顯式呼叫它,系統會“自動”執行該特殊方法。
上面想法聽起來很神奇,甚至有一些不切實際,但其實是完全可以實現的,實現這個需求的技術就是 AOP。AOP 專門用於處理系統中分佈於各個模組(不同方法)中的交叉關注點的問題,在 Java EE 應用中,常常通過 AOP 來處理一些具有橫切性質的系統級服務,如事務管理、安全檢查、快取、物件池管理等,AOP 已經成為一種非常常用的解決方案。
具體實現技術
AspectJ。。。
cglib繼承被代理的類,重寫方法,織入通知