Java中的面向切面程式設計(AOP)

pedro7發表於2021-04-03

一、什麼是AOP?

Aspect Oriented Programming ,即面向切面程式設計

  • AOP是對物件導向程式設計的一個補充。
  • 它的目的是將複雜的需求分解為不同的切面,將散佈在系統中的公共功能集中解決。
  • 它的實際含義是在執行時將程式碼切入到類的指定方法、指定位置上,將不同方法的同一個位置抽象為一個切面物件,並對該物件進行程式設計。

下面是AOP的一個示意圖
AOP示意圖

二、AOP的優點和一些概念

1、AOP的優點
  • 降低模組之間的耦合度
  • 使系統更容易擴充套件
  • 更好的程式碼複用
  • 非業務程式碼更加集中,不分散,便於統一管理
  • 業務程式碼更加簡潔純粹,不摻雜其他的程式碼的影響
2、AOP中出現的一些概念
  • 切面:橫切關注點,被模組化的抽象物件
  • 通知:切面物件完成的工作(非業務程式碼)
  • 目標:被通知的物件(即被橫切的物件)
  • 代理:切面、通知、目標混合之後的物件
  • 連線點:通知要插入業務程式碼的具體位置(如Spring實現中的JoinPoint)
  • 切點:AOP通過切點定位到連線點

三、使用動態代理實現AOP

1、新增依賴
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aop</artifactId>
	<version>5.0.11.RELEASE</version>
</dependency>

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aspects</artifactId>
	<version>5.0.11.RELEASE</version>
</dependency>
2、建立一個計算器介面Cal,定義四個方法

動態代理的類的方法應當都由介面來實現,這樣才方便使用動態代理物件執行方法
計算器介面Cal

3、建立介面的實現類CalImpl

高耦合的寫法,每次列印日誌都要手動完成:
高耦合的寫法

4、使用動態代理進行優化

上方程式碼中,日誌資訊和業務邏輯的耦合性很高,不利於程式碼的維護。使用AOP可以進行優化,我們可以使用動態代理實現AOP:
給業務程式碼找一個代理,列印日誌資訊的工作交給代理來做。這樣的話業務程式碼就只需要關注自身業務即可。
(1)去掉手動輸出的日誌資訊
去掉手動輸出的日誌資訊
(2).代理輔助類的編寫和使用(動態代理的核心)

我們建立的並不是所謂的代理類,而是一個可以幫助我們返回代理物件的輔助類,這個輔助類有兩個功能

  1. 接收委託物件並依次返回代理物件
  2. 處理代理物件呼叫方法的過程
    建立代理輔助類
    值得注意的是:
  • 注意別忘了給委託物件賦值的那一步
  • 建立代理動態代理物件時傳入的方法保證了代理類擁有原類的全部功能
  • 呼叫代理物件的方法時會自動呼叫invoke方法
    (3)測試
    測試動態代理實現AOP

四、使用Spring實現AOP

動態代理實現AOP比較複雜,不易理解。Spring框架對AOP進行了封裝,使用Spring框架可以用物件導向的思想實現AOP。Spring框架中不需要建立輔助類,只需要建立一個切面物件,將所有的非業務程式碼在切面物件中完成即可(但實際上Spring框架底層依然會根據切面類和代理類來生成代理物件。)

1、新增依賴
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aop</artifactId>
	<version>5.0.11.RELEASE</version>
</dependency>

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aspects</artifactId>
	<version>5.0.11.RELEASE</version>
</dependency>

 <dependency>
	 <groupId>org.springframework</groupId>
	 <artifactId>spring-context</artifactId>
	 <version>5.0.11.RELEASE</version>
 </dependency>
2、建立一個計算器介面Cal,定義四個方法

當使用Spring實現時,這一步非必須!直接在實體類裡面定義方法也可
計算器介面

3、定義實體類,實現方法

注意需要加上Component註解把他交給IoC
定義實體類,實現方法

4、建立切面類

建立切面類
類定義處的兩個註解

  • @Aspect表示該類是一個切面類
  • @Component將該類的物件注入到IoC容器(切面類和實體類都需要加上這個註解)

方法處的註解

  • @Before表示方法執行的具體位置和時機是方法開始時

  • @After類似Before,不過位置是方法的最後
    在這裡插入圖片描述

  • @AfterReturning在下文有作解釋

  • @AfterThrowing在下文有作解釋

5、在spring.xml中進行配置

Spring配置檔案

  • context:component-scan指掃描com.pedro包中的所有類,如果該類同時新增了component註解,則將該類掃描IoC容器中。即IoC管理它的物件
  • aop:aspectj-autoproxy讓Spring容器結合切面類和目標類自動生成代理物件
6、使用

使用Spring的AOP
用代理物件呼叫方法就會自動執行它本身的方法和切面類中的非業務程式碼

為什麼類名首字母要小寫?
當使用註解配置bean時,預設id(別名)就是首字母改為小寫的類名。若想修改,就在實體類的註解處加上自定義的名字即可。如@Component("test"),這樣的話在getBean的時候就可以使用自定義的別名了,即xx.getBean("test")

7、兩個特殊的After註解

(1)AfterReturning

用於在獲取返回值後執行一段非業務程式碼
AfterReturning

注:因為有兩個引數,這裡的value標籤名被標出,而上面的before、after等註解只有一個引數,所以省略了value

結合上面的其他註解,會輸出:

div方法的引數是[6,2]
div方法執行完畢
div方法的結果是3

(2)AfterThrowing

切面類的AfterThrowing註解,用於在丟擲異常後執行一段非業務程式碼
AfterThrowing
結合上面的其他註解,會輸出:

div方法的引數是[6,0]
div方法執行完畢
div方法丟擲的異常:java.lang.ArithmeticException: / by zero

2021.4.3

相關文章