美文网首页Spring Boot
自定义AOP与事务

自定义AOP与事务

作者: lyz999999 | 来源:发表于2021-07-10 21:52 被阅读0次

背景

       最近在写一个业务实现:主线程生成订单,然后使用自定义 AOP 的 @AfterReturning 注解,通过新建线程异步查询该条订单并推送到其他系统。
       开发环境中,整个流程执行一直没问题(重复测试了很多遍)。一放到线上,问题就出来了。异步查询这一步,在线上一直查不到新生成的这条订单。但主线程返回后会调起支付,在支付业务中能正常查到。(.............莫名其妙的bug)

分析

当前环境(线上/线下)

  1. 数据库为默认事务隔离级别REPEATABLE-READ可重复读。
  2. Spring 中开启了事务。

问题产生原因

  1. 主线程与异步子线程不属于同一个事务。
    Spring的事务是通过ThreadLocal来保证线程安全的,使用ThreadLocal来存储Connection,不同的线程Connection不一样,所以不在同一个事务中。
  2. 在主线程事务未提交时,异步子线程无法读取到主线程事务中的数据。

为什么线下开发环境中没有出现问题?

       自我分析:极有可能是线下开发环境中,机器执行速度较慢,每次执行到异步子线程中查询前,主线程都已经提交了事务;而线上机器执行速度快,执行异步子线程查询操作时,主线程还未提交事务,导致查询不存来。

解决问题

主要思路

  1. 控制事务范围,即使主线程中事务在自定义 AOP 执行之前,提交事务。
  2. Spring 中事务也是使用 AOP 来控制的,通过设置order值来控制,切面加载顺序。
  3. order值越大,优先级越小,反之越大。

order取值范围

package org.springframework.core;

public interface Ordered {
    int HIGHEST_PRECEDENCE = -2147483648; // 2^31
    int LOWEST_PRECEDENCE = 2147483647; // 2^31 - 1

    int getOrder();
}
注:其实所有切面order值不能取到最高优先级,会报错
java.lang.IllegalStateException: No MethodInvocation found: Check that an AOP invocation is in progress, 
and that the ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, 
note that advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!

       ExposeInvocationInterceptor是一个调用器的拦截器,打开起源吗可以看到

@Override
public int getOrder() {
        return PriorityOrdered.HIGHEST_PRECEDENCE + 1; //即-2147483648+1
}

       所有AOP切面(包括事务)优先级在这个值之前都会报错,所以order值设置应大于该值

自定义 AOP 切面类中注解设置加载顺序

@Component
@Aspect
@Order(-200)
public class McGoodsAop {
}
注:初步测试,@Order注解写在方法中,不生效

Springboot中设置事务加载优先级

@SpringBootApplication
@EnableTransactionManagement(order = 0) // order = 0 设置事务加载优先级
public class ApiApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiApplication.class, args);
    }

}

总结

       1. order值设置的是加载顺序,如事务优先级大于自定义 AOP 切面,则 AOP 切面内业务将被包含在事务中,可控制事务回滚等;如事务优先级小于自定义 AOP 切面,则在执行自定义AOP中代码时,事务已经完成(提交)。
       2. 事务和自定义AOP默认优先级(不主动设置)均为最低级,优先级相同情况下,以事务 AOP 优先。
       3. 因为用的是返回通知@AfterRunning,刚开始以为事务优先级高会在执行自定义 AOP 中代码前提交事务(这是错误的),导致耽误了不少时间。
       4. 事务和自定义 AOP 修改order值,热部署都不生效,需要重启应用。

order优先级补充

       通过aop编写的代码会在运行时进行织入(动态代理),织入的过程类似于方法调用,是一个入栈出栈的过程。


入栈出栈示意图

相关文章

网友评论

    本文标题:自定义AOP与事务

    本文链接:https://www.haomeiwen.com/subject/nkrlpltx.html