V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
movq
V2EX  ›  程序员

SpringAOP 的执行顺序到底是怎么样的?

  •  
  •   movq · 2022-10-09 13:48:04 +08:00 · 1719 次点击
    这是一个创建于 809 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我使用spring-boot-starter-parent 2.7.4测试了一下,得到的结论是这样的: (我的切点的方法就是输出“汪汪汪”)

    不使用@Around通知:

    before ......
    汪汪汪
    afterReturning ......
    after ......
    

    使用@Around通知:

    around before......
    before ......
    汪汪汪
    afterReturning ......
    after ......
    around after......
    
    1. 按照网上的说法,应该顺序是这样的:around before -> before -> 切点方法 -> around after -> after -> after returning

    2. 为什么我的测试结果中afterReturning竟然还跑到after的前面去了, around after 跑到最后面去了?

    我的@Aspect代码`

    @Aspect
    public class MyAspect {
    
        @Pointcut("execution(* com.example.springboot_test_1005.Dog.bark(..))")
        public void pointCut() {
        }
    
        @Before("pointCut()")
        public void before() {
            System.out.println("before ......");
        }
    
        @After("pointCut()")
        public void after() {
            System.out.println("after ......");
        }
    
        @AfterReturning("pointCut()")
        public void afterReturning() {
            System.out.println("afterReturning ......");
        }
    
        @AfterThrowing("pointCut()")
        public void afterThrowing() {
            System.out.println("afterThrowing ......");
        }
    
        @Around("pointCut()")
        public void around(ProceedingJoinPoint jp) throws Throwable {
            System.out.println("around before......");
            // 回调目标对象的原有方法
            jp.proceed();
            System.out.println("around after......");
        }
    }
    
    

    被代理的类:

    @Component
    public class Dog {
        void bark(){
            System.out.println("汪汪汪");
        }
    }
    
    10 条回复    2022-10-10 10:41:32 +08:00
    movq
        1
    movq  
    OP
       2022-10-09 13:59:40 +08:00
    optional
        2
    optional  
       2022-10-09 14:05:33 +08:00 via iPhone
    正常写代码依赖这个顺序不是把路走窄了吗。。
    八股文问这个不去也罢
    xy90321
        3
    xy90321  
       2022-10-09 15:30:13 +08:00   ❤️ 1
    我怎么觉得你的结果是符合文档说明的?
    https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-ataspectj-advice-ordering

    是找的资料不对吧
    xy90321
        4
    xy90321  
       2022-10-09 15:41:22 +08:00 via iPhone   ❤️ 1
    @movq
    看了下感觉是这个图不太对
    虽然我好久不写切面了,不过根据文档来看
    你最好把不同 advice 的优先度理解为一个 V 字模型

    意味着
    around 的 before 跑的最早
    around 的 after 跑的最晚

    这样才能确保 around 有最高优先级,可以 override 其他 advice 的处理
    sumika
        5
    sumika  
       2022-10-09 16:46:39 +08:00
    你找的网上的说法是 spring4 的顺序,代码里用的是 spring5 吧,这两个版本顺序不一样
    movq
        6
    movq  
    OP
       2022-10-09 16:47:14 +08:00   ❤️ 1
    @xy90321 我也查了下,发现是图不对。csdn 上面瞎说的东西害死人。可以看这两个 github issue

    https://github.com/spring-projects/spring-framework/pull/24673

    https://github.com/spring-projects/spring-framework/issues/25186
    movq
        7
    movq  
    OP
       2022-10-09 16:48:44 +08:00
    @sumika 5.2.7 改了
    threeroseing0
        8
    threeroseing0  
       2022-10-10 09:32:35 +08:00
    @movq 上述的 PR 应该是没有 Merge 的,可以看下 5.2.7 开始新增的注释
    // Note: although @After is ordered before @AfterReturning and @AfterThrowing,
    // an @After advice method will actually be invoked after @AfterReturning and
    // @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
    // invokes proceed() in a `try` block and only invokes the @After advice method
    // in a corresponding `finally` block.
    movq
        9
    movq  
    OP
       2022-10-10 10:01:20 +08:00
    @threeroseing0
    那个 PR 被开发者看到了,然后开发者改了代码,逻辑和 PR 提出的要求是一样的:
    上面第二个 github 连接里面最后一个 activity:
    jhoeller mentioned this issue on 3 Dec 2020
    Clarify intended advice execution behavior in Spring version 5.2.7+
    点进去看代码是在 5.2.x 的代码里面的
    nothingistrue
        10
    nothingistrue  
       2022-10-10 10:41:32 +08:00
    你网上的说法不对。第一,around before/after 必定与 before/after 对应出现,要么 around 在外,即 around before — before — after — around after ,要么 around 在内,即 before — around before — around after — after ,你网上那种顺序不符合常理 。第二,先执行方法后执行 after 切面,同时 return 是在方法内部的,所以 afterReturning 早于 after 更复合常规。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5818 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 02:26 · PVG 10:26 · LAX 18:26 · JFK 21:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.