Spring AOP之@Around,@AfterReturning使用、切不進(jìn)去的解決方案
本文主要舉幾個工作中典型AOP的實操案例,還有經(jīng)常出現(xiàn)的問題(切不進(jìn)去,ctrl+左鍵跳不到被切方法中)等等。
本文對于AOP的實現(xiàn)原理概不討論,百度一搜有的是。
AOP的使用背景和好處
比如A模塊是公司的核心模塊,這塊代碼未經(jīng)允許不得輕易篡改。
但是你又有新的需求,需要在公司的核心模塊的某個方法上進(jìn)行增強(比如在執(zhí)行核心方法的之前打印自定義日志,或者修改該核心方法的入?yún)⒑头祷刂档鹊龋?/p>
這樣你就可以在不修改核心模塊源碼的情況下,對源代碼的方法進(jìn)行增強,擴展原來方法的一些功能。
這樣既能保證源代碼不被破壞,又可以擴展源代碼現(xiàn)有的功能。
一、幾種使用姿勢
1、@AfterReturning和@Before
@AfterReturning是后置方法,在目標(biāo)方法執(zhí)行后執(zhí)行,@Before是前置方法,在目標(biāo)方法執(zhí)行前執(zhí)行
它們一般配合JoinPoint來使用(不能配合ProceedingJoinPoint,會報錯)。
直接看例子:
被切的方法:
@Service
public class OriFuncImpl implements OriFunc{
@Override
public String ori(String str){
System.out.println("執(zhí)行了原方法");
return str;
}
}使用@AfterReturning 和 @Before:
@Aspect
@Component
public class AopFunc {
@Pointcut("execution(* com.daji.aop_test.OriFuncImpl.ori(..))")
public void test() {
}
@Before("test()")
public void before(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs(); //獲取方法入?yún)?
System.out.println("原方法的入?yún)⑹牵?+args[0]);
System.out.println("原方法執(zhí)行前會先執(zhí)行我??!");
}
@AfterReturning("test()")
public void after(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs(); //獲取方法入?yún)?
System.out.println("原方法執(zhí)行后會執(zhí)行我?。?);
}
}
如果遇到異常,則不執(zhí)行。
- 當(dāng)連接點方法成功執(zhí)行后,返回通知方法才會執(zhí)行,如果連接點方法出現(xiàn)異常,則返回通知方法不執(zhí)行。
- 返回通知方法在目標(biāo)方法執(zhí)行成功后才會執(zhí)行,所以,返回通知方法可以拿到目標(biāo)方法(連接點方法)執(zhí)行后的結(jié)果。
@AfterReturning獲取被切方法返回值,篡改返回參數(shù):
在注解中增加returning參數(shù)即可: returning = “methodResult”
@Pointcut("execution(* com.daji.aop_test.AopTestController.test1(..))")
public void publish() {
}
@AfterReturning(value = "publish()",returning = "methodResult")
public Object afterReturningPublish(JoinPoint joinPoint, Object methodResult) {
//獲取方法返回值
String returnJson = JSONObject.toJSONString(methodResult);
Object[] args = joinPoint.getArgs();
System.out.println("原方法執(zhí)行后會執(zhí)行我?。?);
//這個返回值可以被我們篡改。
return methodResult;
}
其實這個返回值也不是能任意篡改的:
- 答案來了:可以改變返回值,但是分情況,
不能改變:
- 第一種情況:如果返回的對象,改變了對象的引用地址,這種情況,是不能改變返回對象中的值的
- 第二種情況:如果返回的對象是一個基本數(shù)據(jù)類型,或者是String的值,是不能改變返回值的,尤其是String這種final類型的。
可以改變:
- 直接使用傳入的object對象,改變其中的值,是可以的。
2、@Around
@Around是環(huán)繞通知,既可以控制入?yún)?,還可以控制原方法的執(zhí)行和返回值
常常配合ProceedingJoinPoint來使用。
直接看例子:
被切的方法:
@Service
public class OriFuncImpl implements OriFunc{
@Override
public String ori(String str){
System.out.println("執(zhí)行了原方法");
return str;
}
}
使用@Around:
@Aspect
@Component
public class AopFunc {
@Pointcut("execution(* com.daji.aop_test.OriFuncImpl.ori(..))")
public void modifyReturn() {
}
@Around("modifyReturn()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
Object result = joinPoint.proceed(args);
return result;
}
}
3、@Around可以篡改返回值,篡改入?yún)?/h3>
需要ProceedingJoinPoint的配合
注意一定要將@Around修飾的方法用Object修飾其返回值,并且返回原方法執(zhí)行的結(jié)果,如下圖所示:

篡改入?yún)⒁粯拥牡览恚恍枰鄹南聢D中的 args數(shù)組,然后讓其傳入proceed中,即可完成篡改入?yún)ⅰ?/p>
如下圖所示:

所以,這個@Around比較萬能,尤其是配合ProceedingJoinPoint的使用。使AOP能做的事情更多了。
引申一下JoinPoint 和 ProceedingJoinPoint的關(guān)系:
- ProceedingJoinPoint 只能在@Around中使用
- JoinPoint也可以獲取入?yún)ⅲ╣etArgs()),它可以用于@Before 和 @AfterReturning
- Proceedingjoinpoint 繼承了 JoinPoint 。是在JoinPoint的基礎(chǔ)上暴露出 proceed 這個方法。它們之間的關(guān)系如下圖:

4、@Around如果不執(zhí)行proceed(),那么原方法將不會執(zhí)行
二、使用AOP常見的問題和bug
1、切不進(jìn)去
檢查是否有如下注解:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
檢查完畢后檢查切面類,看看有沒有以下注解:

2、ctrl+鼠標(biāo)左鍵不能自動跳到被切方法
正常情況如圖:

如果你存在上述問題,檢查你有沒有安裝下列插件:

如果你是idea社區(qū)版,那么默認(rèn)是沒有的,你要么自己下,要么換成正式版。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring 應(yīng)用中集成 Apache Shiro的方法
這篇文章主要介紹了Spring 應(yīng)用中集成 Apache Shiro的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05
Java springboot里注解大全和使用指南(最新整理)
在Java Spring Boot中,注解是簡化開發(fā)、提高效率的關(guān)鍵工具,這篇文章給大家介紹Java springboot里注解大全和使用指南,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2026-03-03
Spring事務(wù)控制策略及@Transactional失效問題解決避坑
這篇文章主要為大家介紹了Spring事務(wù)控制策略及@Transactional失效問題解決避坑,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
Mybatis獲取自增主鍵的兩種實現(xiàn)原理小結(jié)
MyBatis通過useGeneratedKeys和兩種方式適配不同數(shù)據(jù)庫的自增主鍵生成,利用JDBC接口和KeyGenerator實現(xiàn)高效獲取與回寫,下面就來介紹一下2025-08-08
restTemplate未設(shè)置連接數(shù)導(dǎo)致服務(wù)雪崩問題以及解決
面對線上問題,仔細(xì)分析原因,及時調(diào)整配置,能有效解決問題,本文詳細(xì)描述了線上遇到流量突增引發(fā)的問題,通過查看代碼和連接池信息,分析出問題的原因是連接池滿了,連接池大小配置不足以應(yīng)對大并發(fā)流量,通過調(diào)整連接池大小配置2024-10-10
Java簡單方法實現(xiàn)子任務(wù)耗時統(tǒng)計
在并發(fā)編程中,我們經(jīng)常需要將一個大任務(wù)拆分成多個子任務(wù)并行執(zhí)行,但隨之而來的問題是如何準(zhǔn)確統(tǒng)計每個子任務(wù)的耗時,下面我們來看看如何使用Java實現(xiàn)吧2026-01-01
Java如何向指定文件操作一段內(nèi)容(增加,刪除均可使用本方法)
這篇文章主要介紹了Java如何向指定文件操作一段內(nèi)容(增加,刪除均可使用本方法),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12

