背景
项目中需要用到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类名,越小越靠外层.