你真的确定Spring AOP的执行顺序吗,java实用教程第四版电子版

本文探讨了Spring Boot 2.2.5.RELEASE和2.3.4.RELEASE中Spring AOP执行顺序的差异,发现@Around通知在@After之后执行。作者通过查阅文档和代码验证,揭示了从Spring 5.2.7开始,相同@Aspect类内的通知执行顺序调整,遵循@Around > @Before > @After > @AfterReturning > @AfterThrowing的规则,这与之前的版本不同。
摘要由CSDN通过智能技术生成
  • 在切点之后织入

  • @throws Throwable

*/

@After(“webLog()”)

public void doAfter() throws Throwable {

LOGGER.info("=========================================== End ===========================================");

}

/**

  • 环绕

  • @param proceedingJoinPoint

  • @return

  • @throws Throwable

*/

@Around(“webLog()”)

public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

long startTime = System.currentTimeMillis();

Object result = proceedingJoinPoint.proceed();

// 打印出参

LOGGER.info(“Response Args : {}”, result);

// 执行耗时

LOGGER.info(“Time-Consuming : {} ms”, System.currentTimeMillis() - startTime);

return result;

}

代码感觉完全没有问题,难道新版本的SpringBoot出Bug了。

显然,成熟的框架不会在这种大方向上犯错误,那会不会是新版本的SpringBoot把@After和@Around的顺序反过来了?

其实事情也没有那么简单。

Spring AOP执行顺序

==================================================================================

我们先来回顾下Spring AOP执行顺序。

我们在网上查找关于SpringAop执行顺序的的资料,大多数时候,你会查到如下的答案:

正常情况

========================================================================

你真的确定Spring AOP的执行顺序吗

异常情况

========================================================================

你真的确定Spring AOP的执行顺序吗

多个切面的情况

===========================================================================

你真的确定Spring AOP的执行顺序吗

所以@Around理应在@After之前,但是在SprinBoot 2.3.4.RELEASE版本中,@Around切切实实执行在了@After之后。

当我尝试切换回2.2.5.RELEASE版本后,执行顺序又回到了@Around–>@After

探究顺序错误的真相

=============================================================================

既然知道了是SpringBoot版本升级导致的问题(或者说顺序变化),那么就要来看看究竟是哪个库对AOP执行的顺序进行了变动,毕竟,SpringBoot只是“形”,真正的内核在Spring。

我们打开pom.xml文件,使用插件查看spring-aop的版本,发现SpringBoot 2.3.4.RELEASE 版本使用的AOP是spring-aop-5.2.9.RELEASE。

而2.2.5.RELEASE对应的是spring-aop-5.2.4.RELEASE

于是我去官网搜索文档,不得不说Spring由于过于庞大,官网的文档已经到了冗杂的地步,不过最终还是找到了:

https://docs.spring.io/spring-framework/docs/5.2.9.RELEASE/spring-framework-reference/core.html#aop-ataspectj-advice-ordering

你真的确定Spring AOP的执行顺序吗

As of Spring Framework 5.2.7, advice methods defined in the same @Aspect class that need to run at the same join point are assigned precedence based on their advice type in the following order, from highest to lowest precedence: @Around, @Before, @After, @AfterReturning, @AfterThrowing.

我粗浅的翻译一下重点:

从Spring5.2.7开始,在相同@Aspect类中,通知方法将根据其类型按照从高到低的优先级进行执行:@Around,@Before ,@After,@AfterReturning,@AfterThrowing。

这样看其实对比不明显,我们再回到老版本,也就是2.2.5.RELEASE对应的spring-aop-5.2.4.RELEASE,当时的文档是这么写的:

What happens when multiple pieces of advice all want to run at the same join point? S

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

pring AOP follows the same precedence rules as AspectJ to determine the order of advice execution. The highest precedence advice runs first “on the way in” (so, given two pieces of before advice, the one with highest precedence runs first). “On the way out” from a join point, the highest precedence advice runs last (so, given two pieces of after advice, the one with the highest precedence will run second).

简单翻译:在相同@Aspect类中Spring AOP遵循与AspectJ相同的优先级规则来确定advice执行的顺序。

再挖深一点,那么AspectJ的优先级规则是什么样的?

我找了AspectJ的文档:

https://www.eclipse.org/aspectj/doc/next/progguide/semantics-advice.html

你真的确定Spring AOP的执行顺序吗

At a particular join point, advice is ordered by precedence.

A piece of around advice controls whether advice of lower precedence will run by calling proceed. The call to proceed will run the advice with next precedence, or the computation under the join point if there is no further advice.

A piece of before advice can prevent advice of lower precedence from running by throwing an exception. If it returns normally, however, then the advice of the next precedence, or the computation under the join pint if there is no further advice, will run.

Running after returning advice will run the advice of next precedence, or the computation under the join point if there is no further advice. Then, if that computation returned normally, the body of the advice will run.

Running after throwing advice will run the advice of next precedence, or the computation under the join point if there is no further advice. Then, if that computation threw an exception of an appropriate type, the body of the advice will run.

Running after advice will run the advice of next precedence, or the computation under the join point if there is no further advice. Then the body of the advice will run.

大伙又要说了,哎呀太长不看!简短地说,Aspectj的规则就是上面我们能够在网上查阅到的顺序图展示的那样,依旧是老的顺序。

代码验证

========================================================================

我把业务逻辑从代码中删除,只验证下这几个advice的执行顺序:

/**

  • 日志切面

*/

@Aspect

@Component

public class WebLogAspect {

private final static Logger LOGGER = LoggerFactory.getLogger(WebLogAspect.class);

/** 以 controller 包下定义的所有请求为切入点 */

@Pointcut(“execution(public * com.xx.xxx.xxx.controller….(…))”)

public void webLog() {}

/**

  • 在切点之前织入

  • @param joinPoint

  • @throws Throwable

*/

@Before(“webLog()”)

public void doBefore(JoinPoint joinPoint) throws Throwable {

LOGGER.info("-------------doBefore-------------");

}

@AfterReturning(“webLog()”)

public void afterReturning() {

LOGGER.info("-------------afterReturning-------------");

}

@AfterThrowing(“webLog()”)

public void afterThrowing() {

LOGGER.info("-------------afterThrowing-------------");

}

/**

  • 在切点之后织入

  • @throws Throwable

*/

@After(“webLog()”)

public void doAfter() throws Throwable {

LOGGER.info("-------------doAfter-------------");

}

/**

  • 环绕

  • @param proceedingJoinPoint

  • @return

  • @throws Throwable

*/

@Around(“webLog()”)

public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

long startTime = System.currentTimeMillis();

LOGGER.info("-------------doAround before proceed-------------");

Object result = proceedingJoinPoint.proceed();

LOGGER.info("-------------doAround after proceed-------------");

return result;

}

我们将版本改为2.2.5.RELEASE,结果如图:

你真的确定Spring AOP的执行顺序吗

我们将版本改为2.3.4.RELEASE,结果如图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值