前言
本文主要舉幾個工作中典型AOP的實操案例,還有經常出現的問題(切不進去,ctrl+左鍵跳不到被切方法中)等等。
本文對于AOP的實作原理概不讨論,百度一搜有的是。
AOP的使用背景和好處
比如A子產品是公司的核心子產品,這塊代碼未經允許不得輕易篡改。
但是你又有新的需求,需要在公司的核心子產品的某個方法上進行增強(比如在執行核心方法的之前列印自定義日志,或者修改該核心方法的入參和傳回值等等)
這樣你就可以在不修改核心子產品源碼的情況下,對源代碼的方法進行增強,擴充原來方法的一些功能。
這樣既能保證源代碼不被破壞,又可以擴充源代碼現有的功能。
一、幾種使用姿勢
1、@AfterReturning和@Before
@AfterReturning是後置方法,在目标方法執行後執行,@Before是前置方法,在目标方法執行前執行
它們一般配合JoinPoint來使用(不能配合ProceedingJoinPoint,會報錯)。直接看例子:
被切的方法:
@Service
public class OriFuncImpl implements OriFunc{
@Override
public String ori(String str){
System.out.println("執行了原方法");
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(); //擷取方法入參
System.out.println("原方法的入參是:"+args[0]);
System.out.println("原方法執行前會先執行我!!");
}
@AfterReturning("test()")
public void after(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs(); //擷取方法入參
System.out.println("原方法執行後會執行我!!");
}
}
2、@Around
@Around是環繞通知,既可以控制入參,還可以控制原方法的執行和傳回值
常常配合ProceedingJoinPoint來使用。直接看例子:
被切的方法:
@Service
public class OriFuncImpl implements OriFunc{
@Override
public String ori(String str){
System.out.println("執行了原方法");
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可以篡改傳回值,篡改入參
需要ProceedingJoinPoint的配合
注意一定要将@Around修飾的方法用Object修飾其傳回值,并且傳回原方法執行的結果,如下圖所示:
篡改入參一樣的道理,隻需要篡改下圖中的 args數組,然後讓其傳入proceed中,即可完成篡改入參。如下圖所示:
是以,這個@Around比較萬能,尤其是配合ProceedingJoinPoint的使用。使AOP能做的事情更多了。
引申一下JoinPoint 和 ProceedingJoinPoint的關系:
- ProceedingJoinPoint 隻能在@Around中使用
- JoinPoint也可以擷取入參(getArgs()),它可以用于@Before 和 @AfterReturning
- Proceedingjoinpoint 繼承了 JoinPoint 。是在JoinPoint的基礎上暴露出 proceed 這個方法。它們之間的關系如下圖:
4、@Around如果不執行proceed(),那麼原方法将不會執行
二、使用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社群版,那麼預設是沒有的,你要麼自己下,要麼換成正式版。