spring tx @Transactional 详解 `Advisor`、`Target`、`ProxyFactory
在Spring中,@Transactional注解的处理涉及到多个关键组件,包括Advisor、Target、ProxyFactory等。下面是详细的解析和代码示例,解释这些组件是如何协同工作的。
1. 关键组件介绍
1.1 Advisor
Advisor是一个Spring AOP的概念,它包含了切点(Pointcut)和通知(Advice)。在事务管理中,TransactionAttributeSourceAdvisor是一个典型的Advisor。
1.2 Target
Target是指被代理的目标对象,即实际执行业务逻辑的对象。
1.3 ProxyFactory
ProxyFactory是Spring提供的用于创建代理对象的工厂类。它可以使用JDK动态代理或CGLIB创建代理对象。
2. @Transactional的处理流程
- 解析注解:Spring扫描
@Transactional注解。 - 创建Advisor:创建包含事务处理逻辑的
Advisor。 - 创建代理对象:使用
ProxyFactory为目标对象创建代理对象,并将Advisor加入到代理对象中。
3. 代码示例
3.1 配置类
首先,通过@EnableTransactionManagement启用事务管理。
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;@Configuration
@EnableTransactionManagement
public class AppConfig {// DataSource, EntityManagerFactory, TransactionManager beans configuration
}
3.2 目标对象和接口
定义一个业务接口和其实现类:
public interface MyService {void myTransactionalMethod();
}@Service
public class MyServiceImpl implements MyService {@Override@Transactionalpublic void myTransactionalMethod() {// 业务逻辑System.out.println("Executing myTransactionalMethod");}
}
3.3 ProxyFactory和Advisor
使用ProxyFactory和TransactionAttributeSourceAdvisor来创建代理对象并处理事务:
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;public class ProxyFactoryExample {public static void main(String[] args) {// 创建目标对象MyService target = new MyServiceImpl();// 创建事务属性源TransactionAttributeSource transactionAttributeSource = new NameMatchTransactionAttributeSource();// 创建事务拦截器TransactionInterceptor transactionInterceptor = new TransactionInterceptor();transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource);// 创建AdvisorDefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();advisor.setAdvice(transactionInterceptor);// 创建ProxyFactoryProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(target);proxyFactory.addAdvisor(advisor);// 创建代理对象MyService proxy = (MyService) proxyFactory.getProxy();// 调用代理对象的方法proxy.myTransactionalMethod();}
}
4. 详细解释
4.1 创建目标对象
MyService target = new MyServiceImpl();
这是被代理的目标对象,它包含了业务逻辑,并使用了@Transactional注解。
4.2 创建事务属性源
TransactionAttributeSource transactionAttributeSource = new NameMatchTransactionAttributeSource();
TransactionAttributeSource用于解析事务属性。NameMatchTransactionAttributeSource是一个实现类,可以基于方法名称匹配事务属性。
4.3 创建事务拦截器
TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource);
TransactionInterceptor实现了MethodInterceptor接口,用于在方法调用前后处理事务逻辑。
4.4 创建Advisor
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setAdvice(transactionInterceptor);
DefaultPointcutAdvisor包含了事务拦截器,可以在匹配的方法上应用事务逻辑。
4.5 创建ProxyFactory
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
ProxyFactory用于创建代理对象。它将目标对象和Advisor结合起来,生成代理对象。
4.6 创建代理对象并调用方法
MyService proxy = (MyService) proxyFactory.getProxy();
proxy.myTransactionalMethod();
通过ProxyFactory.getProxy()方法创建代理对象,并调用代理对象的方法。这时,事务拦截器会在方法调用前后执行事务处理逻辑。
5. 总结
通过以上代码示例,可以看出Spring如何解析@Transactional注解,并使用Advisor、Target和ProxyFactory创建代理对象来处理事务逻辑。这些组件协同工作,实现了自动的事务管理。
proxyFactory源码
targetSource与代理对象是两个对象,
在调用代理对象的时候,实际上是要被DynamicAdvisedInterceptor拦截,之后在拦截方法中执行执行拦截器调用链,并把targetSource传给拦截器。
相当于把targetSource对象(非类)作为成员变量传递给代理对象,然后对targetSource对象的方法调用增强。
类->BeanDefinition->bean初始化->为bean添加后置处理器,替换bean对象为proxy对象,其中bean对象作为代理对象的成员变量targetSource,代理对象通过在拦截方法中对targetSource对象的方法调用前后执行advisor的方法。
对比 @Configuration对@bean方法的处理,是直接生成子类,子类重写@bean方法,子类作为BeanDefinition替换原始@Configuration注解的类, 因此在子类中的this调用就是对子类重写的方法调用。
//CglibAopProxy
/*** General purpose AOP callback. Used when the target is dynamic or when the* proxy is not frozen.*/private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {private final AdvisedSupport advised;public DynamicAdvisedInterceptor(AdvisedSupport advised) {this.advised = advised;}@Override@Nullablepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;Object target = null;TargetSource targetSource = this.advised.getTargetSource();try {if (this.advised.exposeProxy) {// Make invocation available if necessary.oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...target = targetSource.getTarget();Class<?> targetClass = (target != null ? target.getClass() : null);List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);Object retVal;// Check whether we only have one InvokerInterceptor: that is,// no real advice, but just reflective invocation of the target.if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {// We can skip creating a MethodInvocation: just invoke the target directly.// Note that the final invoker must be an InvokerInterceptor, so we know// it does nothing but a reflective operation on the target, and no hot// swapping or fancy proxying.Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = invokeMethod(target, method, argsToUse, methodProxy);}else {// We need to create a method invocation...// 链式调用retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}retVal = processReturnType(proxy, target, method, retVal);return retVal;}finally {if (target != null && !targetSource.isStatic()) {targetSource.releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}}}@Overridepublic boolean equals(@Nullable Object other) {return (this == other ||(other instanceof DynamicAdvisedInterceptor &&this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));}/*** CGLIB uses this to drive proxy creation.*/@Overridepublic int hashCode() {return this.advised.hashCode();}}
//ReflectiveMethodInvocation
@Override@Nullablepublic Object proceed() throws Throwable {// We start with an index of -1 and increment early.if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match.InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {return dm.interceptor.invoke(this);}else {// Dynamic matching failed.// Skip this interceptor and invoke the next in the chain.return proceed();}}else {// It's an interceptor, so we just invoke it: The pointcut will have// been evaluated statically before this object was constructed.//调用 @Transactional事务拦截器return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}
//TransactionInterceptor@Nullablepublic Object invoke(MethodInvocation invocation) throws Throwable {Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {@Nullablepublic Object proceedWithInvocation() throws Throwable {// 拦截器链式调用return invocation.proceed();}public Object getTarget() {return invocation.getThis();}public Object[] getArguments() {return invocation.getArguments();}});}

相关文章:
spring tx @Transactional 详解 `Advisor`、`Target`、`ProxyFactory
在Spring中,Transactional注解的处理涉及到多个关键组件,包括Advisor、Target、ProxyFactory等。下面是详细的解析和代码示例,解释这些组件是如何协同工作的。 1. 关键组件介绍 1.1 Advisor Advisor是一个Spring AOP的概念,它包…...
`CyclicBarrier` 是 Java 中的一个同步辅助工具类,它允许一组线程相互等待,直到所有线程都达到了某个公共屏障点(barrier point)
CyclicBarrier 是 Java 中的一个同步辅助工具类,它允许一组线程相互等待,直到所有线程都达到了某个公共屏障点(barrier point)。当所有线程都到达屏障点时,它们可以继续执行后续操作。CyclicBarrier 的特点是可以重复使…...
华为机试HJ108求最小公倍数
华为机试HJ108求最小公倍数 题目: 想法: 要找到输入的两个数的最小公倍数,这个最小公倍数要大于等于其中最大的那个数值,遍历最大的那个数值的倍数,最大的最小公倍数就是输入的两个数值的乘积 input_number_list i…...
Debezium报错处理系列之第114篇:No TableMapEventData has been found for table id:256.
Debezium报错处理系列之第114篇:Caused by: com.github.shyiko.mysql.binlog.event.deserialization.MissingTableMapEventException: No TableMapEventData has been found for table id:256. Usually that means that you have started reading binary log within the logic…...
开发者必看:MySQL主从复制与Laravel读写分离的完美搭配
介绍 主从同步配置的主要性不用多说,本文将详细介绍了如何在MySQL数据库中设置主从复制,以及如何在Laravel框架中实现数据库的读写分离。 通过一系列的步骤,包括修改MySQL配置、创建同步账户、获取二进制日志文件名和位置、导出主服务器数据…...
二战架构师,拿下
前言 已经许久更新文章了,并不是因为我懒了,而是在备考系统架构师考试。个人感觉还是比较幸运的,低分飘过。现阶段任务也算完成了,记录一下感受。 什么是软考 软考,全称“计算机技术与软件专业技术资格(…...
泛微开发修炼之旅--35关于基于页面扩展和自定义按钮实现与后端交互调用的方法
文章链接:35关于基于页面扩展和自定义按钮实现与后端交互调用的方法...
原创作品—数据可视化大屏
设计数据可视化大屏时,用户体验方面需注重以下几点:首先,确保大屏信息层次分明,主要数据突出显示,次要信息适当弱化,帮助用户快速捕捉关键信息。其次,设计应直观易懂,避免复杂难懂的…...
AdaBoost集成学习算法理论解读以及公式为什么这么设计?
本文致力于阐述AdaBoost基本步骤涉及的每一个公式和公式为什么这么设计。 AdaBoost集成学习算法基本上遵从Boosting集成学习思想,通过不断迭代更新训练样本集的样本权重分布获得一组性能互补的弱学习器,然后通过加权投票等方式将这些弱学习器集成起来得到…...
uniapp内置组件uni.navigateTo跳转后页面空白问题解决
文章目录 导文空白问题 导文 在h5上跳转正常 但是在小程序里面跳转有问题 无任何报错 页面跳转地址显示正确,但页面内容为空 空白问题 控制台: 问题解决: 方法1: 可能是没有注册的问题,把没注册的页面 注册一下。 方…...
使用树莓派进行python开发,控制电机的参考资料
网站连接:https://www.cnblogs.com/kevenduan?page1 1、简洁的过程步骤, 2、有代码示例, 3、有注意事项,...
protobuf的使用
protobuf:是一种数据格式,独立于平台,独立于语言,是一种二进制格式,可以存储更加复杂的数据结构,比如图,树,结构体,类 作用: 1.持久化:把数据存…...
笔记15:while语句编程练习
练习一: 编写程序,求 2^24^26^2...n^2? -直到累加和大于或等于 10000 为止,输出累加和 -输出累加式中的项数,以及最大的数 n #include<stdio.h> int main() {int sum 0;int i 1;int n 0;while(sum < 10000)//将sum…...
打开excel时弹出stdole32.tlb
问题描述 打开excel时弹出stdole32.tlb 如下图: 解决方法 打开 Microsoft Excel 并收到关于 stdole32.tlb 的错误提示时,通常意味着与 Excel 相关的某个组件或类型库可能已损坏或不兼容。 stdole32.tlb 是一个用于存储自动化对象定义的类型库&#x…...
349. 两个数组的交集
哈喽!大家好,我是奇哥,一位专门给面试官添堵的职业面试员 文章持续更新,可以微信搜索【小奇JAVA面试】第一时间阅读,回复【资料】更有我为大家准备的福利哟! 文章目录 一、题目二、答案三、总结 一、题目 …...
重庆交通大学数学与统计学院携手泰迪智能科技共建的“智能工作室”
2024年7月4日,重庆交通大学数学与统计学院与广东泰迪智能科技股份有限公司携手共建的“智能工作室”授牌仪式在南岸校区阳光会议室举行。此举标志着数统学院与广东泰迪公司校企合作新篇章的开启,也预示着学院在智能科技教育领域的深入探索和实践。 广东…...
Pandas在生物信息学中的应用详解
Pandas在生物信息学中的应用详解 引言 生物信息学作为一门将计算机科学和生物学相结合的跨学科领域,正随着高通量实验技术的飞速发展而日益重要。Pandas,作为Python中一个强大的数据处理库,为生物信息学研究提供了便捷高效的数据处理和分析…...
ByteMD富文本编辑器的vue3配置
Git地址:GitHub - bytedance/bytemd: ByteMD v1 repository 控制面板输入 npm install bytemd/vue-next 下载成功后在src/main.ts中引用 import "bytemd/dist/index.css";引入后保存,下面是一些插件,比如说我用到gmf和hightLight&…...
基于antdesign封装一个react的上传组件
项目中遇到了一个上传的需求,看了一下已有的代码很粗糙,而且是直接引用andt的组件,体验不太好,自己使用FormData对象封装了一个上传组件,仅供参考。 代码如下: /*** FileUploadModal* description - 文件选…...
ARM裸机:一步步点亮LED(汇编)
硬件工作原理及原理图查阅 LED物理特性介绍 LED本身有2个接线点,一个是LED的正极,一个是LED的负极。LED这个硬件的功能就是点亮或者不亮,物理上想要点亮一颗LED只需要给他的正负极上加正电压即可,要熄灭一颗LED只需要去掉电压即可…...
LSTM门控机制原理解析与工业级调优实战
1. 为什么今天还要认真学LSTM?——一个被低估但从未过时的序列建模基石你可能已经注意到,现在打开任何一篇讲大模型、讲NLP前沿的文章,标题里不是“Transformer”就是“LLM”,仿佛RNN时代早已尘封进教科书的附录。但上周我帮一家做…...
GHelper终极指南:华硕笔记本轻量级性能调控开源工具
GHelper终极指南:华硕笔记本轻量级性能调控开源工具 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbook, Expe…...
2025最权威的十大AI辅助论文工具实测分析
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 聚焦大语言模型架构创新以及训练优化展开研究的是DeepSeek论文,该模型运用混合专…...
基于Dify低代码平台构建红队自动化工作流:从AI赋能到实战部署
1. 项目概述与核心价值 最近在整理红队自动化工具链时,我深度体验了 din4e/DifyDSL4RedTeam 这个项目。简单来说,这是一个基于 Dify 低代码平台构建的、专门为红队场景设计的自动化工作流集合。在 AI 大模型能力日益渗透到安全领域的今天,…...
大语言模型赋能人文社科研究:混合量化设计框架与实践指南
1. 项目概述:当“文科”遇见“大模型”“大语言模型赋能人文社科研究”这个标题,乍一听可能有点“跨界”的意味。在很多人印象里,人文社科研究——无论是历史学、社会学、文学还是哲学——其核心是思辨、诠释与批判,是“文科生”在…...
GitHub Profile动态化:用SVG与Twitter API打造个人技术名片
1. 项目概述与核心价值 最近在折腾个人主页和博客的访客统计时,发现了一个挺有意思的开源项目—— tommyjepsen/twblocks 。简单来说,这是一个能让你在GitHub个人主页(就是那个README.md文件)上,动态展示你最近在Tw…...
Fathom-DeepResearch:大语言模型的长程信息检索与知识合成技术
1. 项目背景与核心价值去年在处理一个金融领域的知识图谱项目时,我遇到了一个棘手问题:当需要从数百万份研究报告中提取跨5年时间维度的关联信息时,传统检索系统要么返回碎片化结果,要么陷入"语义重复"的泥潭。这正是Fa…...
CANN/CANN CVE ID申请指导书
CVE ID申请指导书 【免费下载链接】community 本项目是CANN开源社区的核心管理仓库,包含社区的治理章程、治理组织、通用操作指引及流程规范等基础信息 项目地址: https://gitcode.com/cann/community 1 目的 为确保CANN开源社区在漏洞披露过程中࿰…...
AI与运筹优化融合:从预测后优化到端到端决策的实战解析
1. 项目概述:当运筹优化遇见人工智能在运筹学与工业工程领域干了十几年,我最大的感触是:最耗时的往往不是求解一个模型,而是“造”出这个模型本身。传统的优化建模高度依赖领域专家的经验,他们需要将模糊的业务需求&am…...
【2026年最新】网安学习路线!最详细没有之一!看了这么多分享网安学习路线的一个详细的都没有!
零基础小白,到就业!入门到入土的网安学习路线! 在各大平台搜的网安学习路线都太粗略了。。。。看不下去了! 我把自己报班的系统学习路线,整理拿出来跟大家分享了! 建议的学习顺序: 一、网络安…...
