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

2022-10-09 13:48:04 +08:00
 movq

我使用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("汪汪汪");
    }
}
1507 次点击
所在节点    程序员
10 条回复
movq
2022-10-09 13:59:40 +08:00
optional
2022-10-09 14:05:33 +08:00
正常写代码依赖这个顺序不是把路走窄了吗。。
八股文问这个不去也罢
xy90321
2022-10-09 15:30:13 +08:00
我怎么觉得你的结果是符合文档说明的?
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-ataspectj-advice-ordering

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

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

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

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

https://github.com/spring-projects/spring-framework/issues/25186
movq
2022-10-09 16:48:44 +08:00
@sumika 5.2.7 改了
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
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
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 更复合常规。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/885506

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX