Spring AOP中增强Advice的执行顺序
- Spring AOP中Advice分类
- 同一Apsect中不同类型Advice执行顺序- 配置基础环境
- 实验结果
- 结论
 
- 不同Aspect中Advice执行顺序- 实验一: Aspect1为高优先级,Aspect2为低优先级- 实验结果
 
- 实验二: Aspect1为低优先级,Aspect2为高优先级- 实验结果
 
- 结论
 
- 实验一: 
- 参考资料:
本文主要验证Spring AOP中Advice的执行顺序问题。(Spring版本: 5.3.23)

创新互联专注于企业成都营销网站建设、网站重做改版、青秀网站定制设计、自适应品牌网站建设、H5开发、成都商城网站开发、集团公司官网建设、成都外贸网站制作、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为青秀等各大城市提供网站开发制作服务。
Spring AOP中Advice分类
Spring AOP中Advice可分为如下五类:
- @Around
- @Before
- @AfterReturning
- @AfterThrowing
- @After
Advice相关概念参考
同一Apsect中不同类型Advice执行顺序
配置基础环境
- 依赖版本
- Spring 版本为: 5.3.23
- Spring Boot 版本为: 2.6.12
- aspectjweaver 版本: 1.9.9.1
- 定义Spring Boot启动类
package sakura.springinaction;
@SpringBootApplication
@EnableAspectJAutoProxy
public class MySpringApplication {
	public static void main(String[] args) {
		SpringApplication.run(MySpringApplication.class, args);
	}
}
- 定义一个用于测试的Controller类
package sakura.springinaction.controller;
@Controller
@Slf4j
public class IndexController {
	@GetMapping("/time")
	@ResponseBody
	public String time() {
		LocalDateTime now = LocalDateTime.now();
		String nowTime = now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
		log.info("Current time: " + nowTime);
		return nowTime;
	}
}
- 定义一个声明式切面 Apsect1
@Slf4j
@Component
@Aspect
public class Aspect1 {
   // 定义 Point Cut 切面
   @Pointcut("execution(public * sakura.springinaction.controller.*.*(..))")
   public void controllerLayer() {
   }
   // 定义Advice
   @Before("controllerLayer()")
   private void beforeAdvice2() {
   	log.info("Aspect_1 # @Before");
   }
   @After("controllerLayer() && @annotation(getMapping)")
   private void afterAdvice1(GetMapping getMapping) {
   	log.info("Aspect_1 # @afterAdvice" + " path: " + Arrays.toString(getMapping.value()));
   }
   @AfterReturning(pointcut = "controllerLayer()", returning = "val")
   private void afterReturningAdvice(Object val) {
   	log.info("Aspect_1 # @AfterReturning" + " returnValue: " + val);
   }
   @AfterThrowing(pointcut = "controllerLayer()", throwing = "thrower")
   private void afterThrowingAdvice(Throwable thrower) {
   	log.info("Aspect_1 # @AfterThrowing" + " thrower: " + thrower.getClass().getName());
   }
   @Around("controllerLayer() && @annotation(getMapping)")
   private Object aroundAdvice(ProceedingJoinPoint pjp, GetMapping getMapping) throws Throwable {
   	// Around 前置处理
   	Stopwatch stopwatch = Stopwatch.createStarted();
   	log.info("Aspect_1 # @Around-Before" + " methodName: " + pjp.getSignature().getName() + ", path: " + Arrays.toString(getMapping.value()));
   	Object result = pjp.proceed();
   	// Around 后置处理
   	log.info("Aspect_1 # @Around-After" + " methodName: " + pjp.getSignature().getName() + ", runTime: " + stopwatch.elapsed(TimeUnit.NANOSECONDS));
   	return result;
   }
}
实验结果
在 发起请求(http://localhost:8080/time) 后,日志输出如图:
结论
在同一个切面(Apsect)定义中对于同一个Join Point而言,不同类型的Advice执行先后顺序依次是:
- @Around前置处理
- @Before
- @AfterReturning/- @AfterThrowing
- @After
- @Around后置置处理
优先级说明:
- 对于进入
Join Point的Advice而言(比如:@Around前置处理,@Before),优先级越高,越先执行;- 对于从
Join Point出来的Advice而言(比如:@Around后置处理,@After),优先级越高,越后执行;- 优先级从高到低依次为:
@Around,@Before,@After,@AfterReturning,@AfterThrowing;
PS:
如果在同一个切面(
Apsect)中定义了两个同类型的Advice(比如定义两个@Before), 对于某个Join Point而言这两个Advice都匹配,那么这两个Advice执行的先后顺序是无法确定的。
不同Aspect中Advice执行顺序
问: 当不同的Aspect中的Advice 都匹配到了同一个Join Point,那么那个Aspect中的Advice 先执行,那个后执行呢?
答: 不确定 ,但是可以通过在class上添加注解@Order指定优先级确定执行顺序(参考文档)
实验一: Aspect1为高优先级,Aspect2为低优先级
- 与Aspect1类似,再定义一个切面类Aspect2,如下
package sakura.springinaction.advice;
import org.springframework.core.annotation.Order;
@Slf4j
@Component
@Aspect
@Order(2)
public class Aspect2 {
  // 定义Advice
  @Before("sakura.springinaction.advice.Aspect1.controllerLayer()")
  private void beforeAdvice2() {
    log.info("Aspect_2 # @Before");
  }
  @After("sakura.springinaction.advice.Aspect1.controllerLayer() && @annotation(getMapping)")
  private void afterAdvice1(GetMapping getMapping) {
    log.info("Aspect_2 # @afterAdvice" + " path: " + Arrays.toString(getMapping.value()));
  }
  @AfterReturning(pointcut = "sakura.springinaction.advice.Aspect1.controllerLayer()", returning = "val")
  private void afterReturningAdvice(Object val) {
    log.info("Aspect_2 # @AfterReturning" + " returnValue: " + val);
  }
  @AfterThrowing(pointcut = "sakura.springinaction.advice.Aspect1.controllerLayer()", throwing = "thrower")
  private void afterThrowingAdvice(Throwable thrower) {
    log.info("Aspect_2 # @AfterThrowing" + " thrower: " + thrower.getClass().getName());
  }
  @Around("sakura.springinaction.advice.Aspect1.controllerLayer() && @annotation(getMapping)")
  private Object aroundAdvice(ProceedingJoinPoint pjp, GetMapping getMapping) throws Throwable {
    Stopwatch stopwatch = Stopwatch.createStarted();
    log.info("Aspect_2 # @Around-Before" + " methodName: " + pjp.getSignature().getName() + ", path: " + Arrays.toString(getMapping.value()));
    Object result = pjp.proceed();
    log.info("Aspect_2 # @Around-After" + " methodName: " + pjp.getSignature().getName() + ", runTime: " + stopwatch.elapsed(TimeUnit.NANOSECONDS));
    return result;
  }
}
- Aspect1添加- @Order注解指定优先级,如下
@Slf4j
@Component
@Aspect
@Order(1)
public class Aspect1 {
  //...
}
此时,Aspect1的优先级比Aspect2的优先级高。
实验结果
实验结果如下:
说明:
高优先级的
Aspect1中的@Around前置处理和@Before先于低优先级的Aspect2执行,而@AfterReturning,@After和@Around后置处理,则低优先级的Aspect2先执行。
实验二: Aspect1为低优先级,Aspect2为高优先级
- 更改两个Aspect中@Order注解优先级,如下:
@Slf4j
@Component
@Aspect
@Order(2)
public class Aspect1 {
  //...
}
@Slf4j
@Component
@Aspect
@Order(1)
public class Aspect2 {
	//...
}
实验结果
实验结果如下:
结论
- 当不同的Aspect中的Advice都匹配到了同一个Join Point,不同Aspect中的Advice执行顺序不确定。
- 通过在Aspect类上添加注解@Order指定优先级,确定执行顺序,执行顺序满足如下规律- 对于@Around前置处理 和@Before两种Advice而言,所在的Aspect优先级越高,越先执行
- 对于@AfterReturning,@AfterThrowing,@After和@Around后置处理 类型的Advice而言,所在的Aspect优先级越高,越后执行
 
- 对于
参考资料:
- Aspect Oriented Programming with Spring
- AspectJ Programming Guide
本文主要目的是记录学习过程,加深对知识点理解; 如有行文有误,望指正。
网站题目:Spring AOP中增强Advice的执行顺序
分享URL:http://www.scyingshan.cn/article/dsopccd.html

 建站
建站
 咨询
咨询 售后
售后
 建站咨询
建站咨询 
 