一、什么是AOP?
Aspect Oriented Programming ,即面向切面編程。
- 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,定義四個方法
動態代理的類的方法應當都由接口來實現,這樣才方便使用動態代理對象執行方法
3、創建接口的實現類CalImpl
高耦合的寫法,每次打印日志都要手動完成:
4、使用動態代理進行優化
上方代碼中,日志信息和業務邏輯的耦合性很高,不利於代碼的維護。使用AOP可以進行優化,我們可以使用動態代理實現AOP:
給業務代碼找一個代理,打印日志信息的工作交給代理來做。這樣的話業務代碼就只需要關注自身業務即可。
(1)去掉手動輸出的日志信息
(2).代理輔助類的編寫和使用(動態代理的核心)
我們創建的並不是所謂的代理類,而是一個可以幫助我們返回代理對象的輔助類,這個輔助類有兩個功能
- 接收委托對象並依次返回代理對象
- 處理代理對象調用方法的過程
值得注意的是:
- 注意別忘了給委托對象賦值的那一步
- 創建代理動態代理對象時傳入的方法保證了代理類擁有原類的全部功能
- 調用代理對象的方法時會自動調用invoke方法
(3)測試
四、使用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中進行配置
context:component-scan
指掃描com.pedro包中的所有類,如果該類同時添加了component注解,則將該類掃描IoC容器中。即IoC管理它的對象aop:aspectj-autoproxy
讓Spring容器結合切面類和目標類自動生成代理對象
6、使用
用代理對象調用方法就會自動執行它本身的方法和切面類中的非業務代碼
為什么類名首字母要小寫?
當使用注解配置bean時,默認id(別名)就是首字母改為小寫的類名。若想修改,就在實體類的注解處加上自定義的名字即可。如@Component("test")
,這樣的話在getBean的時候就可以使用自定義的別名了,即xx.getBean("test")
7、兩個特殊的After注解
(1)AfterReturning
用於在獲取返回值后執行一段非業務代碼
注:因為有兩個參數,這里的value標簽名被標出,而上面的before、after等注解只有一個參數,所以省略了value
結合上面的其他注解,會輸出:
div方法的參數是[6,2]
div方法執行完畢
div方法的結果是3
(2)AfterThrowing
切面類的AfterThrowing注解,用於在拋出異常后執行一段非業務代碼
結合上面的其他注解,會輸出:
div方法的參數是[6,0]
div方法執行完畢
div方法拋出的異常:java.lang.ArithmeticException: / by zero
2021.4.3