一起玩轉微服務(13)——AOP
一、什麼是AOP程式設計
AOP: Aspect Oriented Programming 面向切面程式設計。 面向切面程式設計(也叫面向方面):Aspect Oriented Programming(AOP),是目前軟體開發中的一個熱點。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。 AOP是OOP的延續,是(Aspect Oriented Programming)的縮寫,意思是面向切面(方面)程式設計。 主要的功能是:日誌記錄,效能統計,安全控制,事務處理,異常處理等等。 主要的意圖是:將日誌記錄,效能統計,安全控制,事務處理,異常處理等程式碼從業務邏輯程式碼中劃分出來,通過對這些行為的分離,我們希望可以將它們獨立到非指導業務邏輯的方法中,進而改 變這些行為的時候不影響業務邏輯的程式碼。
注意:AOP不是一種技術,實際上是程式設計思想。凡是符合AOP思想的技術,都可以看成是AOP的實現。
二、AOP程式設計思想
功能: 讓關注點程式碼與業務程式碼分離!
- 關注點
關注點,重複程式碼就叫做關注點; - 切面
關注點形成的類,就叫切面(類)!
面向切面程式設計,就是指 對很多功能都有的重複的程式碼抽取,再在執行的時候網業務方法上動態植入“切面類程式碼”。 - 切入點
執行目標物件方法,動態植入切面程式碼。
可以通過切入點表示式,指定攔截哪些類的哪些方法; 給指定的類在執行的時候植入切面類程式碼。
三、AOP原理剖析
在軟體業,AOP為Aspect Oriented Programming的縮寫,意為:面向切面程式設計,通過預編譯方式和執行期動態代理實現程式功能的統一維護的一種技術。AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函數語言程式設計的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
AOP把軟體系統分為兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特點是,它們經常發生在核心關注點的多處,而各處都基本相似,比如許可權認證、日誌、事務處理。AOP 的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。
AOP中的一些名詞如下:
- 切面(Aspect):一個關注點的模組化,這個關注點可能會橫切多個物件。事務管理是J2EE應用中一個關於橫切關注點的很好的例子。在Spring AOP中,切面可以使用基於模式或者基於@Aspect註解的方式來實現。
- 連線點(Joinpoint):在程式執行過程中某個特定的點,比如某方法呼叫的時候或者處理異常的時候。在Spring AOP中,一個連線點總是表示一個方法的執行。
- 通知(Advice):在切面的某個特定的連線點上執行的動作。其中包括了“around”、“before”和“after”等不同型別的通知(通知的型別將在後面部分進行討論)。許多AOP框架(包括Spring)都是以攔截器做通知模型,並維護一個以連線點為中心的攔截器鏈。
- 切入點(Pointcut):匹配連線點的斷言。通知和一個切入點表示式關聯,並在滿足這個切入點的連線點上執行(例如,當執行某個特定名稱的方法時)。切入點表示式如何和連線點匹配是AOP的核心:Spring預設使用AspectJ切入點語法進行匹配。
- 引入(Introduction):用來給一個型別宣告額外的方法或屬性(也被稱為連線型別宣告(inter-type declaration))。Spring允許引入新的介面(以及一個對應的實現)到任何被代理的物件。例如,你可以使用引入來使一個bean實現IsModified介面,以便簡化快取機制。
- 目標物件(Target Object):被一個或者多個切面所通知的物件。也被稱做被通知(advised)物件。既然Spring AOP是通過執行時代理實現的,這個物件永遠是一個被代理(proxied)物件。
- AOP代理(AOP Proxy):AOP框架建立的物件,用來實現切面契約(例如通知方法執行等等)。在Spring中,AOP代理可以是JDK動態代理或者CGLIB代理。
- 織入(Weaving):把切面連線到其它的應用程式型別或者物件上,並建立一個被通知的物件。這些可以在編譯時(例如使用AspectJ編譯器),類載入時和執行時完成。Spring和其他純Java AOP框架一樣,在執行時完成織入。
四、AOP程式設計使用
註解版本實現AOP
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 開啟事物註解許可權 @Aspect 指定一個類為切面類 @Pointcut("execution(* com.service.UserService.add(..))") 指定切入點表示式 @Before("pointCut_()") 前置通知: 目標方法之前執行 @After("pointCut_()") 後置通知:目標方法之後執行(始終執行) @AfterReturning("pointCut_()") 返回後通知: 執行方法結束前執行(異常不執行) @AfterThrowing("pointCut_()") 異常通知: 出現異常時候執行 @Around("pointCut_()") 環繞通知: 環繞目標方法執行 @Component @Aspect public class AopLog { // 前置通知 @Before("execution(* com.service.UserService.add(..))") public void begin() { System.out.println("前置通知"); } // 後置通知 @After("execution(* com.service.UserService.add(..))") public void commit() { System.out.println("後置通知"); } // 執行通知 @AfterReturning("execution(* com.service.UserService.add(..))") public void returning() { System.out.println("執行通知"); } // 異常通知 @AfterThrowing("execution(* com.service.UserService.add(..))") public void afterThrowing() { System.out.println("異常通知"); } // 環繞通知 @Around("execution(* com.service.UserService.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("環繞通知開始"); proceedingJoinPoint.proceed(); System.out.println("環繞通知結束"); } }
&n