Spring?Aop常見注解與執(zhí)行順序詳解
Spring 一開始最強大的就是 IOC / AOP 兩大核心功能,我們今天一起來學(xué)習(xí)一下 Spring AOP 常見注解和執(zhí)行順序。
Spring Aop 的常用注解
首先我們一起來回顧一下 Spring Aop 中常用的幾個注解:
- @Before 前置通知:目標(biāo)方法之前執(zhí)行
- @After 后置通知:目標(biāo)方法之后執(zhí)行(始終執(zhí)行)
- @AfterReturning 返回之后通知:執(zhí)行方法結(jié)束之前執(zhí)行(異常不執(zhí)行)
- @AfterThrowing 異常通知:出香異常后執(zhí)行
- @Around 環(huán)繞通知:環(huán)繞目標(biāo)方法執(zhí)行
常見問題
1、你肯定知道 Spring , 那說說 Aop 的去全部通知順序, Spring Boot 或者 Spring Boot 2 對 aop 的執(zhí)行順序影響?
2、說說你在 AOP 中遇到的那些坑?
示例代碼
下面我們先快速構(gòu)建一個 spring aop 的 demo 程序來一起討論 spring aop 中的一些細(xì)節(jié)。
配置文件
為了方便我直接使用 spring-boot 進行快速的項目搭建,大家可以使用 idea 的spring-boot 項目快速創(chuàng)建功能,或者去 start.spring.io 上面去快速創(chuàng)建spring-boot 應(yīng)用。(因為本人經(jīng)常手動去網(wǎng)上貼一些依賴導(dǎo)致,依賴沖突服務(wù)啟動失敗等一些問題)。
plugins {
id 'org.springframework.boot' version '2.6.3'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group 'io.zhengsh'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
dependencies {
# 其實這里也可以不增加 web 配置,為了試驗簡單,大家請忽略
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-aop'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}接口類
首先我們需要定義一個接口。我們這里可以再來回顧一下 JDK 的默認(rèn)代理實現(xiàn)的選擇:
如果目標(biāo)對象實現(xiàn)了接口,則默認(rèn)采用JDK動態(tài)代理
如果目標(biāo)對象沒有實現(xiàn)接口,則采用進行動態(tài)代理
如果目標(biāo)對象實現(xiàn)了接口,且強制Cglib,則使用cglib代理
這塊的邏輯在 DefaultAopProxyFactory 大家有興趣可以去看看。
public interface CalcService {
public int div(int x, int y);
}實現(xiàn)類
這里我門就簡單一點做一個除法操作,可以模擬正常也可以很容易的模擬錯誤。
@Service
public class CalcServiceImpl implements CalcService {
@Override
public int div(int x, int y) {
int result = x / y;
System.out.println("====> CalcServiceImpl 被調(diào)用了,我們的計算結(jié)果是:" + result);
return result;
}
}aop 攔截器
申明一個攔截器我們要為當(dāng)前對象增加 @Aspect 和 @Component ,筆者之前也是才踩過這樣的坑,只加了一個。
其實這塊我剛開始也不是很理解,但是我看了 Aspect 注解的定義我就清楚了

這里面根本就沒有 Bean 的定義。所以我們還是乖乖的加上兩個注解。 還有就是如果當(dāng)測試的時候需要開啟Aop 的支持為配置類上增加 @EnableAspectJAutoProxy 注解。
其實 Aop 使用就三個步驟:
1、定義 Aspect 定義切面
2、定義 Pointcut 就是定義我們切入點
3、定義具體的通知,比如: @After, @Before 等。
@Aspect
@Component
public class MyAspect {
@Pointcut("execution(* io.zhengsh.spring.service.impl..*.*(..))")
public void divPointCut() {
}
@Before("divPointCut()")
public void beforeNotify() {
System.out.println("----===>> @Before 我是前置通知");
}
@After("divPointCut")
public void afterNotify() {
System.out.println("----===>> @After 我是后置通知");
}
@AfterReturning("divPointCut")
public void afterReturningNotify() {
System.out.println("----===>> @AfterReturning 我是前置通知");
}
@AfterThrowing("divPointCut")
public void afterThrowingNotify() {
System.out.println("----===>> @AfterThrowing 我是異常通知");
}
@Around("divPointCut")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object retVal;
System.out.println("----===>> @Around 環(huán)繞通知之前 AAA");
retVal = proceedingJoinPoint.proceed();
System.out.println("----===>> @Around 環(huán)繞通知之后 BBB");
return retVal;
}
}測試類
其實我這個測試類,雖然用了 @Test 注解,但是我這個類更加像一個 main 方法把:如下所示:

執(zhí)行結(jié)論
結(jié)果記錄:spring 4.x, spring-boot 1.5.9
無法現(xiàn)在依賴,所以無法試驗
我直接說一下結(jié)論: Spring 4 中環(huán)繞通知是在最里面執(zhí)行的
結(jié)果記錄:spring 版本5.3.15 springboot 版本2.6.3

多切面的情況
多個切面的情況下,可以通過@Order指定先后順序,數(shù)字越小,優(yōu)先級越高。 如下圖所示:

代理失效場景
下面一種場景會導(dǎo)致 aop 代理失效,因為我們在執(zhí)行 a 方法的時候其實本質(zhì)是執(zhí)行 AServer#a 的方法攔截器(MethodInterceptor)鏈, 當(dāng)我們在 a 方法內(nèi)直接執(zhí)行b(), 其實本質(zhì)就相當(dāng)于 this.b() , 這個時候由執(zhí)行 a方法是調(diào)用到 a 的原始對象相當(dāng)于是 this 調(diào)用,那么會導(dǎo)致 b() 方法的代理失效。這個問題也是我們開發(fā)者在開發(fā)過程中最常遇到的一個問題。
@Service
public class AService {
public void a() {
System.out.println("...... a");
b();
}
public void b() {
System.out.println("...... b");
}
}總結(jié)
到此這篇關(guān)于Spring Aop常見注解與執(zhí)行順序的文章就介紹到這了,更多相關(guān)Spring Aop常見注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
實例解析Json反序列化之ObjectMapper(自定義實現(xiàn)反序列化方法)
這篇文章主要介紹了實例解析Json反序列化之ObjectMapper,json自定義序列化的方法,需要的朋友可以了解下。2017-09-09
Java如何將字符串轉(zhuǎn)為數(shù)字int的三種方式詳析
這篇文章主要給大家介紹了關(guān)于Java如何將字符串轉(zhuǎn)為數(shù)字int的三種方式,在編程中我們經(jīng)常需要進行各種數(shù)據(jù)類型之間的轉(zhuǎn)換操作,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10
Java修改eclipse中web項目的server部署路徑問題
這篇文章主要介紹了Java修改eclipse中web項目的server部署路徑,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11
Java @Transactional與synchronized使用的問題
這篇文章主要介紹了Java @Transactional與synchronized使用的問題,了解內(nèi)部原理是為了幫助我們做擴展,同時也是驗證了一個人的學(xué)習(xí)能力,如果你想讓自己的職業(yè)道路更上一層樓,這些底層的東西你是必須要會的2023-01-01

