解决事务执行两次的问题

1. 问题引入

笔者最近在调试spring事务与切面的优先级的时候偶然发现, 事务被执行了两次. 如下图所示:
在这里插入图片描述
执行顺序是 controller方法->事务->自定义切面->事务->业务方法

2.代码

Controller
    @GetMapping("/txTest")
    public String txTest(HttpServletRequest request) {
        SpringProxy proxy=(SpringProxy) test;
        Factory factory=(Factory) test;
        Advised advised=(Advised) test;
        Advisor[] advisors=advised.getAdvisors();
        String result=test.txTest("aop test");
        return "hehe";
    }
Service
	@Transactional
    public String txTest(String msg){
        System.out.println(msg);
        return msg;
    }
切面
@Component
@Aspect
@Order(1)
public class AopTest1 {

    @Pointcut("execution(* com.iline.iot.usercenter.TestImpl.txTest(..))")
    public void pointcut() {}

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println(this.getClass().getSimpleName()+"-around:before");
        Object result=joinPoint.proceed();
        System.out.println(this.getClass().getSimpleName()+"-around:after");
        //int a=3/0;
        return result;
    }

    @Before("pointcut()")
    public void before() {
        System.out.println(this.getClass().getSimpleName()+"-before");
    }

    @After("pointcut()")
    public void after() {
        System.out.println(this.getClass().getSimpleName()+"-after");
    }
}

自定义切面的order值为1, 是比事务的优先级高的. 理论上应该先执行切面around的代码

3.猜想

  1. 难道是系统里有多个事务管理器引起的?
  2. 或者系统里其他地方还有编码式事务?

4.问题分析

service方法的事务和切面最终都会解析为增强(advisor)织入service类, 所以先查看service类, 看看到底事务的advisor有几个.

4.1调试变量, 查看advisor(增强)

先看service的test变量, 如下图所示
在这里插入图片描述
因为spring中所有代理对象都是Advised的子类, 所以可以将test转为Advised类型, 让后查看它的advisors.
查看advosor发现, 怎么只有事务的, 切面的advisor去哪了?
切面的方法明明执行了啊.
切面方法执行输出
查看test的target, 发现其已经被增强过.
在这里插入图片描述
继续将target转为Advised, 查看advisor
在这里插入图片描述
这次可以看到切面的advisor和事务的adviosr, 而且切面的advisor的优先级比事务的高.
但是, 怎么会还有一个事务的增强??? 这样就有一个最外层优先级最高的增强, 下来是切面的增强, 下来又是一个事务的增强了. 这和实际执行情况也是相符合的.
为啥会有两个事务的增强? 下来调试, 分析源码.

4.2 源码分析(advisor解析)

代理对象是在创建bean的时候创建的, 增强是BeanPostProcessor在处理bean的时候引进来并且生成代理对象.
如下图所示
BeanPostProcessor

解析advisor
刚开始AnnotationAwareAspectJAutoProxyCreator类型的 BeanPostProcessor创建了切面和事务的增强.
之后, DefaultAdvisorAutoProxyCreator的processor又织入了事务增强, 这样的话, 这次的事务增强优先级就是最高的.
在这里插入图片描述

在这里插入图片描述

4.3 原因猜想

既然有两个事务增强, 那么有一个肯定是不应该创建的, 怎么判断哪个是不需要的呢?

  1. 第二次创建的事务增强优先级最高, 这是不正常的, 因为切面的优先级高.
  2. 因为AnnotationAwareAspectJAutoProxyCreator解析增强的时候包含了切面的增强, 所以这个processor必须存在.

所以初步分析DefaultAdvisorAutoProxyCreator创建的事务是多余的, 或者系统里就不应该存在DefaultAdvisorAutoProxyCreator这种类型的bean.

4.4 对比其他系统

在这里插入图片描述
查看得知, 其他系统中是没有这个DefaultAdvisorAutoProxyCreator类型的bean的, 所以这个bean有可能是手动创建的.

5.解决问题

在这里插入图片描述
经查看, 确实有两处手动创建了DefaultAdvisorAutoProxyCreator类型的bean, 打断点后发现ShiroConfiguration中的bean被创建了, 如下图所示, 至此真相大白.
在这里插入图片描述
删除掉此处创建bean的代码即可.

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值