【无标题】

发布时间:2023年12月18日


前言

spring boot 单个切面内,多个通知处理一个切点执行的顺序是怎样的?多个切面,多个通知处理一个切点的执行顺序又是怎样的?请看下文:

一、单个切面,多个通知处理一个切点的执行顺序分析

1.单个切面中,多个通知中没有重复的情况下:

同一个切点,通知执行顺序

2.单个切面中,多个通知中存在重复的情况下:

大体逻辑依然是:1.around > 2.before > 切点方法 > 3.around > 4.after > 5.afterReturning(or afterThrowing)
相同类型的通知根据通知方法名称的字典序执行
注: @Order 放在相同类型的通知根据方法上并不会改变同类通知的执行顺序

二、多个切面,多个通知处理一个切点的执行顺序分析

1. 各个切面内部,通知中没有重复的情况下:

在这里插入图片描述
注: 多个切面默认按照切面类名称的字典序执行,@Order注解放在切面类上可以改变切面的执行顺序,值越小,切面越先执行

2. 各个切面内部,通知中有重复的情况下:

整体类似于同心圆,局部与单个切面执行逻辑一致
整体执行顺序如下:
在这里插入图片描述
详细执行顺序如下:
在这里插入图片描述

注: 同一个切面内,相同类型的通知根据通知方法名称的字典序执行

三、验证代码

切面1(示例):

package com.imooc.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Slf4j
//@Order(6)
public class Aspect1 {

    @Pointcut("execution(* com.imooc.controller.HelloController.*(..))")
    private void pointCutMethod() {
    }

    //声明前置通知
//    @Before("pointCutMethod()")
//    public void doBefore2(JoinPoint point) {
//        log.info("Aspect1:doBefore2");
//    }

    //声明前置通知
    @Before("pointCutMethod()")
    public void doBefore1(JoinPoint point) {
        log.info("Aspect1:doBefore1");
    }

    //声明前置通知
//    @Before("pointCutMethod()")
//    public void aBefore(JoinPoint point) {
//        log.info("Aspect1:aBefore");
//    }

    //声明后置通知
    @AfterReturning(pointcut = "pointCutMethod()", returning = "returnValue")
    public void doAfterReturning(JoinPoint point, Object returnValue) {
        log.info("Aspect1:doAfterReturning");
    }


    //声明例外通知
    @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")
    public void doAfterThrowing(Exception e) {
        log.info("Aspect1:doAfterThrowing");
    }


    //声明最终通知
    @After("pointCutMethod()")
    public void doAfter() {
        log.info("Aspect1:doAfter");
    }


    //声明环绕通知
    @Around("pointCutMethod()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        log.info("Aspect1:doAround-1");
        Object obj = pjp.proceed();
        log.info("Aspect1:doAround-2");
        return obj;
    }

}

切面2(示例):

package com.imooc.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Slf4j
//@Order(1)
public class Aspect2 {

    @Pointcut("execution(* com.imooc.controller.HelloController.*(..))")
    private void pointCutMethod() {
    }

    //声明前置通知
    @Before("pointCutMethod()")
    public void doBefore(JoinPoint point) {
        log.info("Aspect2:doBefore");
    }

    //声明后置通知
    @AfterReturning(pointcut = "pointCutMethod()", returning = "returnValue")
    public void doAfterReturning(JoinPoint point, Object returnValue) {
        log.info("Aspect2:doAfterReturning");
    }

    //声明例外通知
    @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")
    public void doAfterThrowing(Exception e) {
        log.info("Aspect2:doAfterThrowing");
    }

    //声明最终通知
    @After("pointCutMethod()")
    public void doAfter() {
        log.info("Aspect2:doAfter");
    }

    //声明环绕通知
    @Around("pointCutMethod()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        log.info("Aspect2:doAround-1");
        Object obj = pjp.proceed();
        log.info("Aspect2:doAround-2");
        return obj;
    }
}

切点(示例):

package com.imooc.controller;

import com.imooc.config.SelfRefreshScope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import java.util.ArrayList;
import java.util.List;

@ApiIgnore
@RestController
@SelfRefreshScope
public class HelloController {

    final static Logger logger = LoggerFactory.getLogger(HelloController.class);

    @GetMapping("/hello")
    public Object hello() {
        logger.info("info: hello~");
        List<String> list = new ArrayList<>();
        return list;
    }

}


总结

spring aop就是一个同心圆,要执行的方法为圆心,最外层的order最小。从最外层按照AOP1、AOP2的顺序依次执行doAround方法,doBefore方法。然后执行method方法,最后按照AOP2、AOP1的顺序依次执行doAfter、doAfterReturn方法。也就是说对多个AOP来说,先before的,一定后after。

文章来源:https://blog.csdn.net/qq_42282792/article/details/135053148
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。