spring aop中各个advice顺序

背景

      项目中需要用到aop切面,但是切点方法上有@Transaction,我自定义了注解切面,但是不知道切点上两个注解切面,哪个先执行,哪个后执行。所以本文就通过实验测试各个aop切面的顺序。

 

测试DEMO

1.同一个aspect的不同advice

测试代码:

//spring aspect
@Aspect
@Component
public class BroundAspect {

    private  Logger logger = LoggerFactory.getLogger(BroundAspect.class);


    @Pointcut("@annotation(cn.wh.test.annotation.PostAction)")
    public void around() {

    }


    @Pointcut("@annotation(cn.wh.test.annotation.PostAction)")
    public void after() {

    }

    @Pointcut("@annotation(cn.wh.test.annotation.PostAction)")
    public void before() {

    }

    @Before("before()")
    public void beforeInterceptor1(JoinPoint joinPoint) {
        logger.info("beforeInterceptor1: 1-before");
    }

    @After("after()")
    public void afterInterceptor1(JoinPoint jp) {
        logger.info("afterInterceptor1: 1-after start.");
    }

    @AfterReturning("after()")
    public void afterReturningInterceptor1(JoinPoint jp) {
        logger.info("afterReturningInterceptor1: 1-afterReturning start.");
    }

    @AfterThrowing("after()")
    public void afterThrowing(JoinPoint joinPoint) {
        logger.info("afterThrowing1: 1-afterThrowing start.");
    }

    @Around("around()")
    public void aroundInterceptor1(ProceedingJoinPoint joinPoint) {

        logger.info("AroundAspect.aroundInterceptor1: 1-around start!!!");

        try {

            Object proceed = joinPoint.proceed();
        } catch (Throwable e) {
            logger.error("AroundAspect.interceptor1: 1-around error:msg={},e={}.", e.getMessage(), e);
            throw new RuntimeException(e);
        }

        logger.info("AroundAspect.aroundInterceptor1: 1-arount end!!!");

        return;
    }
}


//切点方法:
@Service
public class AspectService {

    private Logger logger = LoggerFactory.getLogger(AspectService.class);

    @PostAction("wh")
    public void testAspect() {
        logger.info("AspectService.testAspect: method body!!!");
        return;
    }
}

//测试代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ComponentScan(basePackages = "cn.wh.test")
@EnableAspectJAutoProxy
public class AspectOrderTest {
    
    @Resource
    private AspectService aspectService;

    @Test
    public void testAspect() {
        try {
            aspectService.testAspect();
        } catch (Throwable t) {
            System.out.println("t= " + t);
        }

        System.out.println("over!!!");
    }
}

测试结果:

//正常执行:
15:56:33.308 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-around start!!!
15:56:33.308 [main] INFO cn.wh.test.aspect.BroundAspect - beforeInterceptor1: 1-before
15:56:33.327 [main] INFO cn.wh.test.AspectService - AspectService.testAspect: method body!!!
15:56:33.327 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-arount end!!!
15:56:33.327 [main] INFO cn.wh.test.aspect.BroundAspect - afterInterceptor1: 1-after start.
15:56:33.327 [main] INFO cn.wh.test.aspect.BroundAspect - afterReturningInterceptor1: 1-afterReturning start.
over!!!

//执行异常:
//在切点方法中抛runtimeException,afterThrowing会执行,如果异常不消耗则继续抛出
15:58:21.445 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-around start!!!
15:58:21.445 [main] INFO cn.wh.test.aspect.BroundAspect - beforeInterceptor1: 1-before
15:58:21.459 [main] INFO cn.wh.test.AspectService - AspectService.testAspect: method body!!!
15:58:21.463 [main] INFO cn.wh.test.aspect.BroundAspect - afterInterceptor1: 1-after start.
15:58:21.463 [main] INFO cn.wh.test.aspect.BroundAspect - afterThrowing1: 1-afterThrowing start.
t= java.lang.RuntimeException: java.lang.RuntimeException: test exception.
over!!!

总结:

同一个aspect的各个advice执行顺序:

正常情况:around--->before--->目标方法--->around (end)--->after--->after returning

异常情况:around--->before--->目标方法--->around (end)--->after--->after throwing

2.同一个aspect的相同类型advice

在上面的aspect类中增加一个around方法

//第二个环绕通知
@Around("around()")
public void aroundInterceptor2(ProceedingJoinPoint joinPoint) {
    logger.info("AroundAspect.aroundInterceptor2: 2-around start!!!");
    try {
        Object proceed = joinPoint.proceed();
    } catch (Throwable e) {
        logger.error("AroundAspect.interceptor2: 2-around error:msg={},e={}.", e.getMessage(), e);
    }
    logger.info("AroundAspect.aroundInterceptor2: 2-arount end!!!");
    return;
}

测试结果:

16:09:38.342 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-around start!!!
16:09:38.342 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor2: 2-around start!!!
16:09:38.342 [main] INFO cn.wh.test.aspect.BroundAspect - beforeInterceptor1: 1-before
16:09:38.355 [main] INFO cn.wh.test.AspectService - AspectService.testAspect: method body!!!
16:09:38.355 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor2: 2-arount end!!!
16:09:38.355 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-arount end!!!
16:09:38.355 [main] INFO cn.wh.test.aspect.BroundAspect - afterInterceptor1: 1-after start.
16:09:38.355 [main] INFO cn.wh.test.aspect.BroundAspect - afterReturningInterceptor1: 1-afterReturning start.
over!!!

此时各个advice的order是相同的,将aroundInterceptor2---->aroundInterceptor:

//第二个环绕通知
@Around("around()")
public void aroundInterceptor(ProceedingJoinPoint joinPoint) {
    logger.info("AroundAspect.aroundInterceptor2: 2-around start!!!");
    try {
        Object proceed = joinPoint.proceed();
    } catch (Throwable e) {
        logger.error("AroundAspect.interceptor2: 2-around error:msg={},e={}.", e.getMessage(), e);
    }
    logger.info("AroundAspect.aroundInterceptor2: 2-arount end!!!");
    return;
}
16:12:50.827 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor2: 2-around start!!!
16:12:50.827 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-around start!!!
16:12:50.827 [main] INFO cn.wh.test.aspect.BroundAspect - beforeInterceptor1: 1-before
16:12:50.843 [main] INFO cn.wh.test.AspectService - AspectService.testAspect: method body!!!
16:12:50.843 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-arount end!!!
16:12:50.843 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor2: 2-arount end!!!
16:12:50.843 [main] INFO cn.wh.test.aspect.BroundAspect - afterInterceptor1: 1-after start.
16:12:50.843 [main] INFO cn.wh.test.aspect.BroundAspect - afterReturningInterceptor1: 1-afterReturning start.

结论:

order和aspect名字相同时,会比较intercept方法名,字母越小越在外层,但是advice的相对位置不会改变,比如before和around2

3.同一aspect,多组相同的advice

在上面aspect类中新增:

    //第2个环绕通知
    @Around("around()")
    public void aroundInterceptor3(ProceedingJoinPoint joinPoint) {
        logger.info("AroundAspect.aroundInterceptor3: 3-around start!!!");
        try {

            Object proceed = joinPoint.proceed();
        } catch (Throwable e) {
            logger.error("AroundAspect.interceptor3: 3-around error:msg={},e={}.", e.getMessage(), e);
        }
        logger.info("AroundAspect.aroundInterceptor3: 3-arount end!!!");
        return;
    }

    //第2个前置通知
    @Before("before()")
    public void beforeInterceptor3(JoinPoint joinPoint) {
        logger.info("beforeInterceptor3: 3-before");
    }

    //第2个后置通知
    @After("after()")
    public void afterInterceptor3(JoinPoint jp) {
        logger.info("afterInterceptor3: 3-after start.");
    }

    //第2个后置返回通知
    @AfterReturning("after()")
    public void afterReturningInterceptor3(JoinPoint jp) {
        logger.info("afterReturningInterceptor3: 3-afterReturning start.");
    }

    //第2个后置异常通知
    @AfterThrowing("after()")
    public void afterThrowing3(JoinPoint joinPoint) {
        logger.info("afterThrowing3: 3-afterThrowing start.");
    }

测试结果:

16:44:36.891 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-around start!!!
16:44:36.891 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor3: 3-around start!!!
16:44:36.891 [main] INFO cn.wh.test.aspect.BroundAspect - beforeInterceptor1: 1-before
16:44:36.892 [main] INFO cn.wh.test.aspect.BroundAspect - beforeInterceptor3: 3-before
16:44:36.910 [main] INFO cn.wh.test.AspectService - AspectService.testAspect: method body!!!
16:44:36.911 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor3: 3-arount end!!!
16:44:36.911 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-arount end!!!
16:44:36.911 [main] INFO cn.wh.test.aspect.BroundAspect - afterInterceptor1: 1-after start.
16:44:36.911 [main] INFO cn.wh.test.aspect.BroundAspect - afterInterceptor3: 3-after start.
16:44:36.911 [main] INFO cn.wh.test.aspect.BroundAspect - afterReturningInterceptor1: 1-afterReturning start.
16:44:36.911 [main] INFO cn.wh.test.aspect.BroundAspect - afterReturningInterceptor3: 3-afterReturning start.
over!!!

结论:

同一个aspect相同advice会根据intecept名字排序,字母越小越靠外,但是不同advice的相对位置不变

 

4.不同aspect类

删除上面aspect中的around2方法,增加一个新的aspect类:

@Aspect
@Component
public class AroundAspect2 {

    private Logger logger = LoggerFactory.getLogger(AroundAspect2.class);

    @Pointcut("@annotation(cn.wh.test.annotation.PostAction)")
    public void Around2(){

    }

    @Pointcut("@annotation(cn.wh.test.annotation.PostAction)")
    public void before2(){

    }

    @Pointcut("@annotation(cn.wh.test.annotation.PostAction)")
    public void after2() {

    }

    @Before("before2()")
    public void beforeInterceptor2(JoinPoint jp) {
        logger.info("beforeInterceptor2: 2-before start.");
    }

    @After("after2()")
    public void afterInterceptor2(JoinPoint joinPoint) {
        logger.info("afterInterceptor2: 2-after start.");
    }

    @AfterReturning("after2()")
    public void afterReturningInterceptor2(JoinPoint jp) {
        logger.info("afterReturningInterceptor2: 2-afterReturning start.");
    }

    @AfterThrowing("after2()")
    public void afterThrowing2(JoinPoint joinPoint) {
        logger.info("afterThrowing2: 2-afterThrowing start.");
    }

    @Around("Around2()")
    public void aroundInterceptor2(ProceedingJoinPoint joinPoint) {

        logger.info("aroundInterceptor2: 2-around start.");
        try {
            joinPoint.proceed();
        } catch (Throwable t) {
            logger.info("aroundInterceptor2: 2-t={}.", t);
        }
        logger.info("aroundInterceptor2: 2-around end.");
    }
}

bspect和aspect2都是默认的order,执行结果:

16:20:05.680 [main] INFO cn.wh.test.aspect.AroundAspect2 - aroundInterceptor2: 2-around start.
16:20:05.680 [main] INFO cn.wh.test.aspect.AroundAspect2 - beforeInterceptor2: 2-before start.
16:20:05.681 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'broundAspect'
16:20:05.681 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-around start!!!
16:20:05.681 [main] INFO cn.wh.test.aspect.BroundAspect - beforeInterceptor1: 1-before
16:20:05.701 [main] INFO cn.wh.test.AspectService - AspectService.testAspect: method body!!!
16:20:05.701 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-arount end!!!
16:20:05.701 [main] INFO cn.wh.test.aspect.BroundAspect - afterInterceptor1: 1-after start.
16:20:05.701 [main] INFO cn.wh.test.aspect.BroundAspect - afterReturningInterceptor1: 1-afterReturning start.
16:20:05.701 [main] INFO cn.wh.test.aspect.AroundAspect2 - aroundInterceptor2: 2-around end.
16:20:05.701 [main] INFO cn.wh.test.aspect.AroundAspect2 - afterInterceptor2: 2-after start.
16:20:05.701 [main] INFO cn.wh.test.aspect.AroundAspect2 - afterReturningInterceptor2: 2-afterReturning start.
over!!!

修改aspect2的order:

bspect实现ordered接口
@Override
public int getOrder() {
    return 1;
}



aspect2实现ordered接口
@Override
public int getOrder() {
    return 2;
}
16:34:27.669 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-around start!!!
16:34:27.669 [main] INFO cn.wh.test.aspect.BroundAspect - beforeInterceptor1: 1-before
16:34:27.669 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'aroundAspect2'
16:34:27.670 [main] INFO cn.wh.test.aspect.AroundAspect2 - aroundInterceptor2: 2-around start.
16:34:27.670 [main] INFO cn.wh.test.aspect.AroundAspect2 - beforeInterceptor2: 2-before start.
16:34:27.686 [main] INFO cn.wh.test.AspectService - AspectService.testAspect: method body!!!
16:34:27.686 [main] INFO cn.wh.test.aspect.AroundAspect2 - aroundInterceptor2: 2-around end.
16:34:27.686 [main] INFO cn.wh.test.aspect.AroundAspect2 - afterInterceptor2: 2-after start.
16:34:27.686 [main] INFO cn.wh.test.aspect.AroundAspect2 - afterReturningInterceptor2: 2-afterReturning start.
16:34:27.686 [main] INFO cn.wh.test.aspect.BroundAspect - AroundAspect.aroundInterceptor1: 1-arount end!!!
16:34:27.686 [main] INFO cn.wh.test.aspect.BroundAspect - afterInterceptor1: 1-after start.
16:34:27.686 [main] INFO cn.wh.test.aspect.BroundAspect - afterReturningInterceptor1: 1-afterReturning start.
over!!!

结论:

order越小,越靠外层

 

 

结论

相同aspect:

order和aspect类名字相同,会根据intecept名排优先级,intecept名字字母越小越靠外层,不同advice的相对位置不变,例如:around在before之前

 

不同aspect:

首先根据order排优先级,order越小越靠外层,越大越靠内层;

order相同,比较aspect类名,越小越靠外层.

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值