读懂Spring AOP中通知的执行原理
前言
这个代理类是AOP基于JDK动态代理生成的,当使用代理类调用目标方法时,会执行到org.springframework.aop.framework.JdkDynamicAopProxy#invoke方法中去,后面的调用链也在这里面。
定义一个切面
切面包含了环绕通知(前)、前置通知、增强方法、环绕通知(后、后置通知、带返回值后置通知、异常通知
/**
* 增强计算器的切面
*/
@Component
@Aspect
public class JisuanqiAspect {
//AOP功能==》引入方式的使用
/* @DeclareParents(value = "yuanma.leiqiang.aop.JiSuanQiImpl",
defaultImpl = YinruImpl.class
)
public static Yinru yinru;*/
//各种通知的使用↓
@Pointcut("execution(* com.redis.aop..*(..))")
public void pointCut() {}
@Before(value = "pointCut()")
public void before(JoinPoint joinPoint) throws Exception{
String name = joinPoint.getSignature().getName();
System.out.println("Before增强了方法"+ name);
}
@After(value = "pointCut()")
public void after(JoinPoint joinPoint) throws Exception{
String name = joinPoint.getSignature().getName();
System.out.println("无返回值After增强了方法"+ name);
}
@AfterReturning(value = "pointCut()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) throws Exception{
String name = joinPoint.getSignature().getName();
System.out.println("带返回值After增强了方法"+ name + "结果为"+result);
}
@AfterThrowing(value = "pointCut()")
public void afterThrowing(JoinPoint joinPoint) throws Exception{
String name = joinPoint.getSignature().getName();
System.out.println("方法出现了异常"+ name);
}
@Around(value = "pointCut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
String name = pjp.getSignature().getName();
System.out.println("环绕通知=>方法执行前"+ name);
Object object = pjp.proceed(pjp.getArgs());//执行我们的方法
System.out.println("环绕通知=>方法执行后"+ name);
return object;
}
}
执行结果
上图中有3张图,上面2张为控制台打印的AOP各种类型通知的执行顺序
上两图介绍
图1为执行了异常通知的打印结果:环绕通知(前)→前置通知→增强方法→后置通知→异常通知
图2为正常的结果:环绕通知(前)→前置通知→增强方法→环绕通知(后)→后置通知→带返回值后置通知
可以看出当出现异常后,那种通知是不会被执行的
第三张图
这个图为AOP生成代理类后,使用代理类调用目标方法时执行通知的集合,就是chain集合中的通知会被递归调用,这些方法中看名字就知道是AOP对各个通知方法的调用;
图解通知的执行流程
将图片中的代码归纳在一起
public static void main(String[] args) {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
//ExposeInvocationInterceptor.invoke AOP内置的一个通知,可以不用看
try {
//AspectJAfterThrowingAdvice.invoke 这是异常通知,可以看就是一个try/catch,也就是将后面的执行逻辑全部包含,所以异常通知能捕获异常呢
Object retVal;
//AfterReturningAdviceInterceptor.invoke 带返回值的后置通知,可以看到这里它定义了返回值接收参数
try {
//AspectJAfterAdvice.invoke 无返回值的后置通知,可以看得出,为啥就算目标方法异常了,后置通知还是会执行,因为后置通知的调用在finally中
String name = pjp.getSignature().getName();
System.out.println("环绕通知=>方法执行前" + name);
//执行环绕通知,这里环绕通知会跳转到自己定义的方法中去执行proceed()这个递归方法,在其他的通知类型中proceed()这个方法都是由AOP去执行的,在环绕通知中,是需要我们自己去执行
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
//执行前置通知MethodBeforeAdviceInterceptor.invoke 继续递归
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//最终执行连接点,就我们的目标方法ReflectiveMethodInvocation.proceed
//最终执行连接点,就我们的目标方
//执行前置通知
//执行环绕通知,这里环绕通知会跳转到自己定义的方法中去执行
System.out.println("环绕通知=>方法执行后" + name);
//AspectJAfterAdvice.invoke
} finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
//AfterReturningAdviceInterceptor.invoke
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
//AspectJAfterThrowingAdvice.invoke
} catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
//ExposeInvocationInterceptor.invoke AOP内置的一个通知
} finally {
invocation.set(oldInvocation);
}
}