Spring AOP中增强Advice的执行顺序(spring增强类型并说明特点)

  本篇文章为你整理了Spring AOP中增强Advice的执行顺序(spring增强类型并说明特点)的详细内容,包含有springaop增强处理类有哪些 spring增强类型并说明特点 spring增强器 springboot增强 Spring AOP中增强Advice的执行顺序,希望能帮助你了解 Spring AOP中增强Advice的执行顺序。

  本文主要验证Spring AOP中Advice的执行顺序问题。(Spring版本: 5.3.23)

  Spring AOP中Advice分类

  Spring AOP中Advice可分为如下五类:

  @Around

  @Before

  @AfterReturning

  @AfterThrowing

  @After

  
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优先级越高,越后执行

  以上就是Spring AOP中增强Advice的执行顺序(spring增强类型并说明特点)的详细内容,想要了解更多 Spring AOP中增强Advice的执行顺序的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: