Spring AOP通知种类,执行顺序大揭秘

2,119 阅读2分钟

Spring AOP通知执行顺序

一.通知有哪几种?

1.Around:环绕通知,在方法执行之前和之后调用的通知

2.before:前置通知,在方法执行前调用

3.after:后置通知,在方法执行之后调用的通知

4.afterReturning:方法成功完成或有异常被其他切面catch后调用的通知

5.afterThrowing:当方法抛出异常退出时执行的通知

二.通知的执行顺序是怎么样的?

在一个切面类里面,定义了五种类型的通知,五种通知的切点相同,那么这几种类型的通知的执行顺序是什么样的呢?

说实话,如果不写个切面实际运行,还真难下结论。

@Component
@Aspect
public class LogAspect {
    //切点
    @Pointcut("execution(public * com.netty.use.nettyuse.controller.*.*(..))")
    public void webLog(){}

    @Around(value = "webLog()")
    public Object around(ProceedingJoinPoint pjp) {
        try {
            System.out.println("Around:方法环绕开始.....");
            Object o =  pjp.proceed();
            System.out.println("Around:方法环绕结束,结果是 :" + o);
            return o;
        } catch (Throwable e) {
            System.out.println(pjp.getSignature() + " 出现异常: "+e.getMessage());
            return "";
        }
    }

    @Before(value = "webLog()")
    public void before(JoinPoint pjp) {
        try {
            System.out.println("before方法执行.....");
        } catch (Throwable e) {
            System.out.println(pjp.getSignature() + " 出现异常: "+e.getMessage());
        }
    }

    @After(value = "webLog()")
    public void after(JoinPoint pjp) {
        System.out.println("after方法执行.....");
    }

    @AfterReturning(value = "webLog()")
    public void afterReturning(JoinPoint pjp) {
       System.out.println("afterReturning方法执行.....");
    }

    @AfterThrowing(value = "webLog()")
    public void afterThrowing(JoinPoint pjp) {
        System.out.println("afterThrowing方法执行.....");
    }

}

方法正常情况的结果输出如下:

Around:方法环绕开始.....

before方法执行.....

familyDTO:{}

Around:方法环绕结束,结果是 :

after方法执行.....

afterReturning方法执行.....

通知的执行的顺序如下:

around->before->方法本身->around->after->afterReturning

如果执行的过程中出现了异常,那么输出如下:

Around:方法环绕开始.....

before方法执行.....

familyDTO:{"count":1}

String
com.netty.use.nettyuse.controller.LaController.methodForObjectParam(FamilyDTO) 出现异常: / by zero

after方法执行.....

afterReturning方法执行.....

异常被around通知catch住,afterReturning通知也执行了。

我们去掉around通知,输出如下:

before方法执行.....

familyDTO:{"count":1}

after方法执行.....

afterThrowing方法执行.....

afterThrowing通知在after通知之后执行。

三.通知排序源码:

ReflectiveAspectJAdvisorFactory类的静态代码块中,定义一个比较器:

private static final Comparator<Method> METHOD_COMPARATOR;

static {
   Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
         new InstanceComparator<>(
               Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
         (Converter<Method, Annotation>) method -> {
            AspectJAnnotation<?> annotation =
               AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
            return (annotation != null ? annotation.getAnnotation() : null);
         });
   Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
   METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
}

Spring AOP通知执行顺序

\