@Transaction和自定义切面的执行顺序思考

news/2024/4/24 5:22:58/

场景

平时使用切面去加分布式锁,是先开启事务还是先尝试获得锁?这两者有啥区别?

  • 先获取锁后执行事务 正确姿势
  • 先获取事务,再获取锁,再释放锁,最后提交事务
    1. 这种情况线程不安全,当线程a释放锁,但还未提交事务,线程b此刻拿到锁并抢在线程a之前提交事务,这样就会导致修改覆盖
    2. 如果分布式锁做一些限流措施,也会产生一定的性能损失,不应该每次请求都开启事务后再进行准入判断

@Transaction分析

  1. @EnableTransactionManagement注解中可看到order属性且默认为最低优先级,最后开启事务,最早提交事务
    @Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(TransactionManagementConfigurationSelector.class)public @interface EnableTransactionManagement {boolean proxyTargetClass() default false;AdviceMode mode() default AdviceMode.PROXY;int order() default Ordered.LOWEST_PRECEDENCE; }
  1. 通过TransactionManagementConfigurationSelector查看Aop实现的2种方式PROXY和ASPECTJ
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {/*** {@inheritDoc}* @return {@link ProxyTransactionManagementConfiguration} or* {@code AspectJTransactionManagementConfiguration} for {@code PROXY} and* {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, respectively*/@Overrideprotected String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {case PROXY:return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};case ASPECTJ:return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};default:return null;}}}
  1. 查看PROXY配置类,发现从enableTx(即从@EnableTransactionManagement设置的order值)获取order值设置到advisor的order中(Aop会根据advisor的order从小到大进行排序)
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();advisor.setTransactionAttributeSource(transactionAttributeSource());advisor.setAdvice(transactionInterceptor());advisor.setOrder(this.enableTx.<Integer>getNumber("order")); // 设置@Transactional注解Advisor的orderreturn advisor;}
}
  1. 查看AspectJ配置类, 查看AnnotationTransactionAspect属于AspectJ语法,AspectJ支持的是静态代理,支持以下三种方式编译期织入、编译期织入 和 加载期织入,当设置启动参数-javaagent:D:\repository\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar和事务注解中设置mode=AspectJ方式是通过加载时织入代码,此时包含有@Transactional的public的类和方法在JVM加载类时被修改class静态织入增强的代码,属于最后执行开启事务和最先执行提交事务,即优先级为最低
    Aspect加载时织入
    AspectJ在Spring中的使用
@Configuration
public class AspectJTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public AnnotationTransactionAspect transactionAspect() {AnnotationTransactionAspect txAspect = AnnotationTransactionAspect.aspectOf();if (this.txManager != null) {txAspect.setTransactionManager(this.txManager);}return txAspect;}}

自定义切面分析

  1. @Aspect注解类由方法ReflectiveAspectJAdvisorFactory#getAdvisors最终会解析成InstantiationModelAwarePointcutAdvisorImpl implement Advisor(具体的原理可参考上篇关于SpringAop源码实现文章分析),其中的getOrder()方法是由this.aspectInstanceFactory.getOrder()实现,逻辑分析下面代码
 // ReflectiveAspectJAdvisorFactory#getAdvisors@Overridepublic Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName) {validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());if (expressionPointcut == null) {return null;}return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);}// this.aspectInstanceFactory.getOrder()@Overridepublic int getOrder() {// 当前的实例是否已经注册到Spring容器Class<?> type = this.beanFactory.getType(this.name);if (type != null) {if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {// 如果是单例对象且是Ordered的实现类,则执行getOrder()方法,具体的值由实现类实现return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();}// 如果不是Ordered的实现类,从类上的@Order @Priority注解获取order值,如果没有则默认为最低优先级return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE);}// 默认返回最低优先级return Ordered.LOWEST_PRECEDENCE;}

通过上述分析发现,如果使用@Aspect注解没有指定顺序则为最低的优先级
2. 自定义类实现Advisor,如BeanFactoryTransactionAttributeSourceAdvisor是SpringTransaction的Advisor实现,关于顺序则自己进行实现,如未实现,最终springaop在获取到所有advisors后进行排序,排序类org.springframework.core.annotation.AnnotationAwareOrderComparator 可发现如果没有实现则按照最低优先级处理。
3. 综上自定义切面不管使用何种方式实现如未指定order值,则按最低优先级处理

顺序核心代码分析

通过上述对自定义,@Aspect以及AspectJ静态织入的分析,继续再看获取aop执行链的顺序的核心代码

  1. 执行链的顺序源码位置org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
    //org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisorsprotected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {// 获取所有advisors逻辑:先获取所有spring advisors ,然后再根据@AspectJ的注解创建并返回所有的advisorsList<Advisor> candidateAdvisors = findCandidateAdvisors();List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors); // 对Advisors先进行order值排序,如果是同一个Advisor则根据指定的注解排序,如果注解一样则根据注解对应的方法名排序(具体可看之前发过的SpringAop源码分析)}return eligibleAdvisors;}@Overrideprotected List<Advisor> findCandidateAdvisors() {// Add all the Spring advisors found according to superclass rules.List<Advisor> advisors = super.findCandidateAdvisors();// Build Advisors for all AspectJ aspects in the bean factory.advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());return advisors;}

根据上述代码可知:

  1. 采用jdk or cglib的动态代理对Advisors先进行order值排序
    1. order值相同则判断是否同一个Advisor
      1. 相同Advisor则根据指定的注解排序
        1. 注解相同:根据注解对应的方法名自然顺序排序
        2. 注解不同:按照注解排序
      2. 不同Advisor则根据默认是按照获取到Advisors的顺序排序,Spring的Advisors的顺序是大于AspectJ的aspects的顺序,此外还有相同springAdvisors和AspectJ的aspects各自内部的顺序,这部分取决于registerBeanDefinition的顺序,registerBeanDefinition顺序太过于庞杂,不过一般来说通过ComponentScan指定basepage等方式应该是按照包名的自然顺序排序(不能保证)(重点
    2. order值不同则直接按order值排序
  2. 静态代理时,@Transactional的优先级最低,其他的自定义切面的增强均优先于@Transactional

总结

  • @Transactional事务当model=PROXY时,可指定优先级order,若未指定则为最低优先级,此时注意如果项目中有其他自定义的切面未配置order指,那么@Transactional的优先级是比项目中@Aspect注解自定义的切面高,如果自定义的切面是通过实现Advisor实现的顺序取决于registerBeanDefinition的顺序
  • @Transactional事务当model=ASPECTJ时,项目引入了AspectJ的静态代理,则@Transactional执行的优先级低于基于jdk和cglib的动态代理,需要注意的是需要关注此时自己编写的Aspect的配置是否@Transactional的Aspect配置执行的优先级顺序,关于AspectJ的静态代理顺序不在本文讨论范围,有兴趣可一起讨论
  • 回到开题的分布式锁的注解问题,如果不指定order的情况下,@Transactional的执行优先于分布式锁注解,会引发线程安全问题。

http://www.ppmy.cn/news/967236.html

相关文章

chatGPT 每小时耗电多少

我无法为您提供关于 chatGPT 的耗电量信息&#xff0c;因为我是一个语言模型&#xff0c;没有浏览网页的能力。但是&#xff0c;我可以告诉您&#xff0c;不同的计算机系统和硬件配置会导致耗电量的差异。例如&#xff0c;使用更高端的 GPU 会使计算机更加耗电&#xff0c;而使…

涵子来信——AI的无限未来——谈谈想法

大家好&#xff1a; 这一次&#xff0c;我想要跟大家讲一讲我对AI的看法和未来的展望&#xff0c;谈谈我的想法。 AI&#xff08;Artificial Intelligence&#xff0c;中文人工智能&#xff09;&#xff0c;是我们生活中处处都可以见到的&#xff0c;小到一个语音助手&#x…

无法拥抱新技术?吴 军:ChatGPT不算新技术革命,带不来什么新机会

转载自 | 学人Scholar 吴军&#xff0c;1967年出生&#xff0c;毕业于清华大学和约翰霍普金斯大学&#xff0c;计算机专业博士&#xff0c;前Google高级资深研究员、原腾讯副总裁、硅谷风险投资人。 4月3日晚上&#xff0c;得到直播间邀请到了计算机科学家、自然语言模型专家吴…

AIGC for code(AIGC/AI生成代码/生成式AI之代码生成/AI编程工具/自动编程/自动生成代码/智能编程工具/智能编程系统)

AIGC&#xff0c;Artificial Intelligence Generated Content&#xff0c;人工智能生成内容 AIGC for code&#xff0c;AI生成代码 1 Github Copilot 1.1 简介 Copilot是由微软的子公司Github与openAI共同开发的人工智能&#xff08;AI&#xff09;驱动的编程助手。它能够直…

Edge 浏览器:隐藏功能揭秘与高效插件推荐

文章目录 一、前言二、Edge 的各种奇淫巧计2.1 开启 Edge 分屏功能2.2 启动 Edge 浏览器后直接恢复上次关闭前的页面2.3 解决 Edge 浏览器无法同步账号内容2.4 开启垂直标签页&#xff08;推荐&#xff09;2.5 设置标签分组&#xff08;推荐&#xff09;2.6 设置标签睡眠时间&a…

ChatGPT王炸更新能联网,可与5000个应用交互 网友:太疯狂了

都说chess GPT是AI的iPhone时刻 现在属于它的应用商店来了 open AI刚刚又甩出一个王炸 宣布推出插件功能 赋予chess GPT使用工具联网 运行计算的能力 例如在官方演示中 Chesh GPP 一旦接入数学知识引擎Wolf and Alpha 就再也不用担心数值 计算不精准的问题 并且还开放了open AI…

揭秘“移动云杯”行业赛道——工业行业应用子赛道

【赛道介绍】 借开发者之力&#xff0c;探究多样化场景需求&#xff0c;开拓算网新生态&#xff0c;面向全球开发者&#xff0c;探索多样化算力网络应用场景&#xff0c;鼓励参赛者基于移动云产品能力&#xff0c;开发形成丰富的算力网络创新应用。 【赛程安排】 说明&#xff…

揭秘“移动云杯”行业赛道——行业应用创新子赛道

【赛事介绍】 为助力中国移动算力网络的发展&#xff0c;加速移动云向算力网络演进过程&#xff0c;促进基于移动云产品能力的创新应用与解决方案的丰富&#xff0c;中国移动联合多家单位举办第二届“移动云杯”算力网络应用创新大赛&#xff0c;为算力网络的战略落实提供创新平…

揭秘“移动云杯”行业赛道——医疗行业应用子赛道

【赛道介绍】 借开发者之力&#xff0c;探究多样化场景需求&#xff0c;开拓算网新生态&#xff0c;面向全球开发者&#xff0c;探索多样化算力网络应用场景&#xff0c;鼓励参赛者基于移动云产品能力&#xff0c;开发形成丰富的算力网络创新应用。 【赛题介绍】 1、参赛对象&a…

看这里!解决你对“移动云杯”大赛的所有困惑

对于第二届“移动云杯”大赛 你是否还有很多问号&#xff1f; 不慌 跟着来看下面的大赛Q&A 解决你所有的困惑~ 本次Q&A主要用于解答大赛报名阶段基础问题&#xff0c;针对技术问题大赛组委会将在搜集用户开发问题后在社区论坛发布技术版FAQ&#xff0c;如还有其他问题可…

低代码:放着我来!智慧办公的八大问题

毫无疑问&#xff0c;数字化转型就是一场真正的“降维打击”。数字化转型是每个企业成长发展的必然趋势&#xff0c;但是&#xff0c;据报告表示&#xff0c;企业数字型转型的成功率仅为20%&#xff0c;即使是互联网、高科技的数字化转型的成功率也不超过26%&#xff0c;而传统…

chatgpt赋能python:Python常用的扩展库简介

Python常用的扩展库简介 Python是一种常用的编程语言&#xff0c;其扩展库为程序员提供了丰富的功能。在这篇文章中&#xff0c;我们将介绍一些Python常用的扩展库&#xff0c;并着重标记加粗其标题和结论。 NumPy NumPy是一种用于科学计算的Python库。它提供了一个强大的N维…

chatGPT代替了我的工作,却让他加薪了50%

前言 最近ChatGPT这个技术发展&#xff0c;着实有点让人眼花缭乱&#xff0c;所以&#xff0c;搞来了一份表格&#xff0c;帮你理清它的发展思路。 简单来说&#xff0c;ChatGPT是一种全新聊天机器人模型&#xff0c;也可以称之为“生成型AI”。 点击免费领取&#xff1a; CS…

玩 ChatGPT 的正确姿势「GitHub 热点速览 」

火了一周的 ChatGPT&#xff0c;HG 不允许还有小伙伴不知道这个东西是什么&#xff1f;简单来说就是&#xff0c;你可以让它扮演任何事物&#xff0c;据说已经有人用它开始了颜色文学创作。因为它太火了&#xff0c;所以&#xff0c;本周特推在几十个带有“chatgpt”的项目中选…

ChatGPT 漫游指南 - GitHub 发布 CopiltX 集成 GPT-4

简介 美国东部时间 2023 年 3 月 22 号上午 10 点&#xff0c;开源代码托管平台 GitHub 在 博客[1] 中宣布推出 CopilotX&#xff0c;集成 OpenAI 最新的 GPT-4 模型。 之前的 GitHub Copilot[2] 是基于 OpenAI 的 Codex 模型开发&#xff0c;它是 GPT-3 模型的低配版&#xff…

动嘴就能写代码,GitHub 将 ChatGPT 引入 IDE,重磅发布 Copilot X!

作者 | 屠敏 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 从以前拖拽控件实现低代码开发&#xff0c;到用自然语言也能自动生成代码&#xff0c;AI 工具势要颠覆程序员疯狂敲键盘的日常&#xff0c;微软也终要将 OpenAI 最前沿的技术贯穿到自家业务线的方方面面…

far-planner源码阅读笔记

一位刚刚会用ROS的小白阅读的第一个工程项目。 说明&#xff1a; 该附件的编写方法为set(CMAKE_BUILD_TYPE Debug)后通过vscode逐行调试。主机运行两个ros-noetic的docker容器&#xff0c;用一个容器调试far-planner另一个容器用于练习从far-planner源码中学到的知识&#xff0…

从B 树、B+ 树、B* 树谈到R 树

程序员的成长之路 互联网/程序员/技术/资料共享 关注 阅读本文大概需要 40 分钟。 来自&#xff1a;blog.csdn.net/v_JULY_v/article/details/6530142 第一节、B树、B树、B*树 前言 动态查找树主要有&#xff1a;二叉查找树&#xff08;Binary Search Tree&#xff09;&#x…

哪有这么多从零项目给你开发

往期热门文章&#xff1a;1、从微服务转为单体架构、成本降低 90%&#xff01;是的&#xff0c;你没看反&#xff01; 2、Lombok 造成的翻车事故&#xff0c;太坑了&#xff01; 3、通用的支付系统该如何设计&#xff1f; 4、Java 17 用户采用率在一年内增长了 430% 5、一个中文…

AI面试必刷算法题 附答案和解析 --持续更新中

面试中发现很多同学一股脑优化、润色项目经历&#xff0c;但聊到基本的算法&#xff0c;反而会一脸懵X&#xff0c;得空整理下算法题给大家&#xff0c;希望对你有帮助。 1. tail(head(tail(C))) ( ) 已知广义表: A(a,b), B(A,A), C(a,(b,A),B), 求下列运算的结果:&#xff08…