qq_37133838 2024-12-16 21:27 采纳率: 40%
浏览 27

spring aop 通知顺序问题

学习过程种遇到的一点疑惑在这里提个问答记录一下,看有没有人恰好知道的
首先声明下我的spring-aop版本:

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.10</version> 
        </dependency>


ReflectiveAspectJAdvisorFactory.getAdvisors中有这样一段代码:

img


通过注释可以看出,spring 5.2.7版本前后,spring 通知执行的顺序稍有不一样的地方,我主要的疑问就在这块了

// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
            // to getAdvisor(...) to represent the "current position" in the declared methods list.
            // However, since Java 7 the "current position" is not valid since the JDK no longer
            // returns declared methods in the order in which they are declared in the source code.
            // Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
            // discovered via reflection in order to support reliable advice ordering across JVM launches.
            // Specifically, a value of 0 aligns with the default value used in
            // AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).


这里我在贴下比较顺序的代码(AbstractAdvisorAutoProxyCreator.findEligibleAdvisors):

img


AspectJPrecedenceComparator.sortAdvisors

img


AspectJPrecedenceComparator.compare

img


上面的advisorComparator是判断Aspect切面是否有ordered注解,这里就不展开讲述了,主要看下面comparePrecedenceWithinAspect

img


可以看到5.2.7之后的版本,就是我上面贴的版本:adviceDeclarationOrderDelta是0,而5.2.7之前,则有区别。经过验证之后也会发现After、AfterReturning和AfterThrowing执行的顺序会不同。


我的主要疑问是上面那段注释,说是跟方法声明的顺序有关,但我调整了方法的顺序,执行顺序依然没有发生变化,原因应该是在ReflectiveAspectJAdvisorFactory.getAdvisorMethods方法里会对通知进行排序,如果是这个情况,我真的不明白这段注释的意思,跟JDK有什么关系,因为getAdvisorMethods(具体代码贴在后面)会按方法名称排序。对了我研究的是@Aspect注解的AOP实现,解析类主要是通过ReflectiveAspectJAdvisorFactory,如果有其他AOP实现,其内部调用getAdvisor方法前,是否存在不会对方法进行排序的情况就直接调用getAdvisor方法?如果是这种情况,麻烦贴出相应的源码


备注:在这里贴下getAdvisorMethods方法的实现:

img

img

看代码,应用了两个比较器,一个是按照

Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class

顺序进行排序,然后再按照方法名称进行排序

  • 写回答

1条回答 默认 最新

  • 关注

    以下回复参考:皆我百晓生券券喵儿等免费微信小程序作答:

    你的理解是正确的,Spring AOP中的通知执行顺序确实与方法的声明顺序有关,但主要关联的是Aspect中的通知顺序以及方法上指定的参数。在你的例子中,尽管getAdvisorMethods方法会对通知方法进行排序,但这主要是为了在构建通知列表时保持某种一致性。实际的通知执行顺序主要依赖于你如何配置你的Aspect以及每个通知上的参数。让我们逐步解析这个问题:

    首先,关于注释中的部分:“Prior to Spring Framework 5.2.7, advisors. size() was supplied as the declarationOrderInAspect to getAdvisor(...) to represent the "current position" in the declared methods list.” 这意味着在Spring框架的5.2.7版本之前,通知的执行顺序是根据它们在Aspect类中声明的顺序来确定的。也就是说,第一个声明的通知会有更高的优先级,然后是下一个等等。这种方法的依据是假设方法的声明顺序代表了它们的优先级。但这种方式是不准确的,因为JDK并不保证方法的返回顺序与声明顺序一致。因此,Spring在后来的版本中改变了策略。

    从Spring框架的5.2.7版本开始,无论方法的声明顺序如何,Spring都会将declarationOrderInAspect硬编码为0。这意味着通知的执行顺序不再依赖于它们在Aspect类中的声明顺序。相反,它依赖于通知类型(如@Before、@After等)以及它们是否带有特定的Order注解或@Ordered接口的实现。如果没有指定任何顺序,那么默认的顺序是:@Around > @Before > @After(其中@After实际上是在所有其他通知之后执行的,因为AspectJAfterAdvice.invoke(MethodInvocation)在'try'块中调用proceed(),只在相应的'finally'块中调用@After通知)。然后,对于相同类型的通知(例如多个@After注解的方法),它们将按照方法名称进行排序(这是由methodNameComparator确定的)。这就是为什么你在代码中看到两个比较器:一个基于通知类型,另一个基于方法名称。因此,即使你更改了方法的声明顺序,只要它们的类型和名称保持不变,执行顺序也不会改变。

    关于你提到的其他AOP实现和排序问题:除了Spring AOP之外,还有其他库(如AspectJ)也支持AOP。这些库可能有自己的实现方式和规则来确定通知的执行顺序。因此,如果你正在使用其他库而不是Spring AOP,那么执行顺序可能会受到该库特定实现的影响。你应该查阅相关库的文档以了解其具体行为和规则。

    评论

报告相同问题?

问题事件

  • 创建了问题 12月16日