Spring AOP之@Around,@AfterReturning使用、切不進去的解決方案
本文主要舉幾個工作中典型AOP的實操案例,還有經(jīng)常出現(xiàn)的問題(切不進去,ctrl+左鍵跳不到被切方法中)等等。
本文對于AOP的實現(xiàn)原理概不討論,百度一搜有的是。
AOP的使用背景和好處
比如A模塊是公司的核心模塊,這塊代碼未經(jīng)允許不得輕易篡改。
但是你又有新的需求,需要在公司的核心模塊的某個方法上進行增強(比如在執(zhí)行核心方法的之前打印自定義日志,或者修改該核心方法的入?yún)⒑头祷刂档鹊龋?/p>
這樣你就可以在不修改核心模塊源碼的情況下,對源代碼的方法進行增強,擴展原來方法的一些功能。
這樣既能保證源代碼不被破壞,又可以擴展源代碼現(xiàn)有的功能。
一、幾種使用姿勢
1、@AfterReturning和@Before
@AfterReturning是后置方法,在目標方法執(zhí)行后執(zhí)行,@Before是前置方法,在目標方法執(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í)行。
- 當連接點方法成功執(zhí)行后,返回通知方法才會執(zhí)行,如果連接點方法出現(xiàn)異常,則返回通知方法不執(zhí)行。
- 返回通知方法在目標方法執(zhí)行成功后才會執(zhí)行,所以,返回通知方法可以拿到目標方法(連接點方法)執(zhí)行后的結果。
@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í)行的結果,如下圖所示:
篡改入?yún)⒁粯拥牡览?,只需要篡改下圖中的 args數(shù)組,然后讓其傳入proceed中,即可完成篡改入?yún)ⅰ?/p>
如下圖所示:
所以,這個@Around比較萬能,尤其是配合ProceedingJoinPoint的使用。使AOP能做的事情更多了。
引申一下JoinPoint 和 ProceedingJoinPoint的關系:
- ProceedingJoinPoint 只能在@Around中使用
- JoinPoint也可以獲取入?yún)ⅲ╣etArgs()),它可以用于@Before 和 @AfterReturning
- Proceedingjoinpoint 繼承了 JoinPoint 。是在JoinPoint的基礎上暴露出 proceed 這個方法。它們之間的關系如下圖:
4、@Around如果不執(zhí)行proceed(),那么原方法將不會執(zhí)行
二、使用AOP常見的問題和bug
1、切不進去
檢查是否有如下注解:
<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+鼠標左鍵不能自動跳到被切方法
正常情況如圖:
如果你存在上述問題,檢查你有沒有安裝下列插件:
如果你是idea社區(qū)版,那么默認是沒有的,你要么自己下,要么換成正式版。
總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
使用Java代碼實現(xiàn)RocketMQ的生產(chǎn)與消費消息
這篇文章介紹一下其他的小組件以及使用Java代碼實現(xiàn)生產(chǎn)者對消息的生成,消費者消費消息等知識點,并通過代碼示例介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2024-07-07SpringBoot+Redis實現(xiàn)接口防刷的示例代碼
在實際開發(fā)中,會出現(xiàn)用戶多次點擊發(fā)送請求,本文主要介紹了SpringBoot+Redis實現(xiàn)接口防刷的示例代碼,具有一定的參考價值,感興趣的可以了解一下2024-01-01解析Java的InputStream類并借助其讀取ppt文件
這篇文章主要介紹了Java的InputStream類并借助其讀取ppt文件,講到了InputStream類中一些常用的方法的問題,需要的朋友可以參考下2015-11-11利用SpringDataJPA開啟審計功能,自動保存操作人操作時間
這篇文章主要介紹了利用SpringDataJPA開啟審計功能,自動保存操作人操作時間,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12