首页
学习
活动
专区
圈层
工具
发布

切面方法一多,谁先谁后全靠猜?源码里写得明明白白

工作里写切面,十个里有八个会撞上这个问题:

一个 @Aspect 类里塞了 @Around、@Before、@After 好几个方法,都切同一个目标方法。跑起来一看输出顺序,和自己在文件里写的顺序对不上。

谁先谁后,全靠猜。猜错了,日志顺序乱了是小事,事务边界挪了位置才是大事。

这篇直接把排序源码翻出来。规则就两条,看完不用再猜。

一、先过一个筛子:不是所有方法都参战

解析切面时,Spring 先做一次过滤。

单独定义 @Pointcut 的方法,直接排除——它只是个切点声明,不是切面逻辑,没资格参与排序。

剩下的 @Around、@Before、@After 方法,才是候选。

二、第一级排序:注解类型定生死

排序用的比较器在类里的 static 块初始化,规则的第一级看注解类型:

@Around 排最前,@Before、@After 依次往后,再到 @AfterReturning、@AfterThrowing。

注意,这和你把方法写在文件的哪个位置没有任何关系

两个方法切同一个目标,@Around 的方法写在文件后面、@Before 的写在前面——执行时 around 依然先跑。文件顺序在注解类型面前一文不值。

三、第二级排序:方法名字符串比大小

那两个方法用同一个注解呢?比如两个 @Before?

按方法名的字符串比较排序,小的排前面、先执行。

底层就是 methodName.compareTo() 那套字符串比较规则。方法名叫 zhouBefore1 和 zhouBefore2,"1"比"2"小,前者先执行。

这个规则简单到有点朴素,但 debug 验证过的结论就是它,没有任何隐藏逻辑。

四、为什么要有这套规则

往深想一层:切面方法最终会变成拦截器链,一个接一个 proceed() 下去。链上的顺序就是执行顺序——所以排序发生在生成 Advisor 的时候,不是调用的时候

这也解释了为什么文件书写顺序不算数:Spring 从来没把"你写在哪一行"当成排序依据,它只认注解类型和方法名。

多个切面切同一个方法时还有更外层的排序规则(@Order 登场),那是下一篇的内容,这里先记住单切面内部这两级。

五、一张决策图带走

碰到顺序问题,按这个顺序判断:

注解不同?@Around @Before @After @AfterReturning @AfterThrowing,注解类型定序

注解相同?方法名字符串比大小,小的先执行

以后再看到切面输出顺序"不对",先查这两条,九成问题当场解决。

写在最后

两个字总结这套规则:注解优先,方法名兜底

不过这是单个切面内部的排序。真实项目里往往是多个切面、多个 Advisor Bean 混在一起,那时候就轮到 @Order 出场了——而 @Order 有个坑:标在方法上根本不生效。下一篇用三个 debug 实验说话。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OyqYb5_onvDfdEs6FuxTZQaQ0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券