【Spring 學習筆記 (十一)】基於註解的 Spring AOP
寫在前面:kissing_heart:
大一電子資訊工程新生,請多多關照,希望能在 InfoQ 社群 記錄 自己的學習歷程!
【Spring 學習筆記】系列教程基於 Spring 5.2.10.RELEASE
講解。
一、AOP 簡介
前面說過, Spring 的核心思想就是 IoC 和 AOP ,有關 IoC 的內容已經介紹過一部分了,接下來就來講下 Spring 另一大重點: AOP 。
1、什麼是 AOP
AOP
,“ Aspect Oriented Programming
”,譯為“ 面向切面程式設計
”,和 OOP(面向物件程式設計)類似, 它也是一種程式設計思想
。
2、AOP 的作用(特點)
代理模式
Spring AOP 的實現原理是 代理模式
,AOP 的作用是 通過代理類為原始類增加一些額外功能
:如日誌管理、許可權管理、事務管理、異常管理等一些 非業務性功能
。
無入侵式
與傳統的公共方法不同,Spring AOP 並不是直接呼叫的,AOP 是通過 橫向的抽取機制
實現的。它將一些 非業務的通用功能
抽取出來單獨維護,並 通過配置檔案或註解的形式定義這些功能
要以哪種方式作用在哪個模組中,可以在無須修改任何業務程式碼的基礎上完成對這些通用功能的呼叫和修改,即 無入侵式
的。
解耦合
事務與非事務功能分離,Spring AOP 還減少程式碼的重複,讓我們更專注於專注業務邏輯程式碼。
3、AOP 相關的專業術語
4、AOP 框架
目前最流行的 AOP 實現(框架)主要有兩個,分別為 Spring AOP 和 AspectJ 。
-
注:一般這兩個框架一起整合使用。
二、AOP 入門案例
SpringAOP 的開發有兩種方式,XML 和 註解, 本篇文章及之後的教程都 使用註解開發 演示.
1、新增 AOP 依賴
在 pom.xml
檔案裡新增 Spring AOP
和 AspectJ
的 jar 包依賴
-
Spring AOP使用純 Java 實現,不需要專門的編譯過程和類載入器,在執行期通過代理方式向目標類織入增強程式碼。
-
AspectJ是一個基於 Java 語言的 AOP 框架。從 Spring2.0 開始,Spring AOP 引入對 Aspect 的支援,AspectJ 擴充套件了 Java 語言,提供了一個專門的編譯器,在編譯時提供橫向程式碼的織入。
<dependencies>
<!--包含Spring AOP:有基本的AOP功能-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--AspectJ框架有更強大的AOP功能-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
</dependencies>
複製程式碼
可以看到 spring-context
中已經匯入了 spring-aop
,所以不需要再單獨匯入 spring-aop

2、建立目標介面和實現類
目標介面和實現類就是所謂的 Target(目標),即要被代理的物件。
/*UserDao介面*/
public interface UserDao {
public void add();
public void delete();
public void update();
public void select();
}
/*UserDaoImpl實現類*/
@Repository
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("正在執行 UserDao 的 add 方法");
}
@Override
public void delete() {
System.out.println("正在執行 UserDao 的 delete 方法");
}
@Override
public void update() {
System.out.println("正在執行 UserDao 的 update 方法");
}
@Override
public void select() {
System.out.println("正在執行 UserDao 的 select 方法");
}
}
複製程式碼
3、建立切面類(通知類)
3.1 定義切面 @Aspect
通過 @Aspect 註解將一個 Bean 定義為切面。
@Component//將這個類定義成 Bean
@Aspect//將這個Bean定義為切面
public class MyAdvice {
}
複製程式碼
3.2 定義切點 @Pointcut
在 AspectJ 中,我們可以使用 @Pointcut 註解用來定義一個切點。
//切點方法必須是private,無返回值,無引數
@Pointcut(value ="execution(* com.bighorn.*.*Dao.*(..))")
private void pointCut() {
}
複製程式碼
注意:
-
定義為切點的方法是一個無意義的 private 方法 ,即無引數、無返回值(void)、無方法體
-
@Pointcut 註解中有一個 value 屬性,這個屬性的值就是 切入點表示式 (插個眼在這,下篇文章詳細嗦嗦)
3.3 定義通知
**通知(Advice)**就是將共性功能抽取出來後形成的方法,即對切入點增強的內容
通知有很多型別:前置通知、後置通知、環繞通知、異常通知、返回通知。(插個眼在這,下篇文章詳細嗦嗦)
通知註解中有一個 value 屬性,value 屬性的取值就是這些 通知(Advice) 所要 織入(Weaving) 的 切點(PointCut) ,它既可以是切入點表示式,也可以是切入點引用(切入點對應的方法名稱)
//使用切入點引用
@Before("MyAdvice.pointCut()")
public void beforeAdvice() {
System.out.println("這是前置通知……");
}
//使用切入點表示式
@After(value ="execution(* com.bighorn.*.*Dao.*(..))")
public void afterAdvice(){
System.out.println("這是後置通知……");
}
複製程式碼
3.4 切面類完整程式碼
/*切面類(通知類)*/
@Component//將這個類定義成 Bean
@Aspect//將這個Bean定義為切面
public class MyAdvice {
//切點方法必須是private,無返回值,無引數
@Pointcut(value = "execution(* com.bighorn.*.*Dao.*(..))")
private void pointCut() {
}
//使用切入點引用
@Before("MyAdvice.pointCut()")
public void beforeAdvice() {
System.out.println("這是前置通知……");
}
//使用切入點表示式
@After(value ="execution(* com.bighorn.*.*Dao.*(..))")
public void afterAdvice(){
System.out.println("這是後置通知……");
}
}
複製程式碼
4、啟用 @AspectJ 註解支援
在 Spring 的配置類中 使用@AspectJ 註解
, 開啟 AspectJ 的自動代理
,使用 @ComponentScan 註解開啟註解掃描。
/*Spring核心配置類*/
@Configuration
@ComponentScan("com.bighorn") //開啟註解掃描
@EnableAspectJAutoProxy //開啟 AspectJ 的自動代理
public class SpringConfig {
}
複製程式碼
5、編寫執行程式
public static void main(String[] args) throws SQLException {
//獲取配置類初始化容器
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
//從容器中獲取UserDao物件
UserDao userDao = context.getBean(UserDao.class);
//呼叫userDao的方法
userDao.add();
userDao.delete();
userDao.update();
userDao.select();
}
複製程式碼
執行結果如下,可以發現對每個方法都進行的加強:前置通知和後置通知

寫在後面:beers:
感謝觀看啦:sparkles:
有什麼不足,歡迎指出哦:sparkling_heart:
- “打臉”谷歌雲,說好的超低延遲和可靠性呢?
- 過去的十五年,我們怎樣做 IM?
- 轉轉 K8s 實踐:如何解決容器化帶來的四大問題
- 企業級證券業務中臺探索與實踐
- 雲原生(十八) | Kubernetes 篇之 Kubernetes(k8s)工作負載
- 【原始碼解析】MyBatis 整體架構與原始碼解析
- 見微知著,帶你認認資料分析的大門,站在門口感受一下預測的魅力
- 未來是國產作業系統的鑽石時代,微核心將成為新的發展方向|對話中興新支點作業系統崔黎明
- 【React 原始碼系列】React Hydrate 原理及原始碼剖析
- 花 31 萬元重新設計網站後,我後悔了
- 一文帶你打通 Node 流的"任督二脈"
- RT-Thread 記錄(七、IPC 機制之郵箱、訊息佇列)
- 開發人員應該知道的零信任模型
- 大佬,還記得設計模式的六大設計原則嗎?
- Java 引數傳遞到底是按 值傳遞 還是 引用傳遞 ?
- 資料技術大融合,HSTAP 資料庫有多少想象空間?
- 說了半天跨平臺,今兒咱就來跨跨!(完結篇)——Kubernetes 上手實踐
- 我認為前端的職責可能需要重新劃分
- 使用 External Secrets Operator 管理 Kubernetes 的 Secret
- Android 應用安全機制實現方案探究