0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

spring中声明式事务实现原理猜想

Android编程精选 来源:CSDN博客 作者:一撸向北 2021-10-13 09:20 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

@Transactional注解简介

@Transactional是spring中声明式事务管理的注解配置方式,相信这个注解的作用大家都很清楚。@Transactional注解可以帮助我们把事务开启、提交或者回滚的操作,通过aop的方式进行管理。

通过@Transactional注解就能让spring为我们管理事务,免去了重复的事务管理逻辑,减少对业务代码的侵入,使我们开发人员能够专注于业务层面开发。

我们知道实现@Transactional原理是基于spring aop,aop又是动态代理模式的实现,通过对源码的阅读,总结出下面的步骤来了解实际中,在spring 是如何利用aop来实现@Transactional的功能的。

spring中声明式事务实现原理猜想

首先,对于spring中aop实现原理有了解的话,应该知道想要对一个方法进行代理的话,肯定需要定义切点。在@Transactional的实现中,同样如此,spring为我们定义了以 @Transactional 注解为植入点的切点,这样才能知道@Transactional注解标注的方法需要被代理。

有了切面定义之后,在spring的bean的初始化过程中,就需要对实例化的bean进行代理,并且生成代理对象。

生成代理对象的代理逻辑中,进行方法调用时,需要先获取切面逻辑,@Transactional注解的切面逻辑类似于@Around,在spring中是实现一种类似代理逻辑。

@Transactional作用

根据上面的原理猜想,下面简单介绍每个步骤的源码以进行验证。

首先是@Transactional,作用是定义代理植入点。我们知道代理对象创建的通过BeanPostProcessor的实现类AnnotationAwareAspectJAutoProxyCreatorpostProcessAfterInstantiation方法来实现个,如果需要进行代理,那么在这个方法就会返回一个代理对象给容器,同时判断植入点也是在这个方法中。

那么下面开始分析,在配置好注解驱动方式的事务管理之后,spring会在ioc容器创建一个BeanFactoryTransactionAttributeSourceAdvisor实例,这个实例可以看作是一个切点,在判断一个bean在初始化过程中是否需要创建代理对象,都需要验证一次BeanFactoryTransactionAttributeSourceAdvisor是否是适用这个bean的切点。如果是,就需要创建代理对象,并且把BeanFactoryTransactionAttributeSourceAdvisor实例注入到代理对象中。

前文我们知道在AopUtils#findAdvisorsThatCanApply中判断切面是否适用当前bean,可以在这个地方断点分析调用堆栈,AopUtils#findAdvisorsThatCanApply一致调用,最终通过以下代码判断是否适用切点。

  • AbstractFallbackTransactionAttributeSource#computeTransactionAttribute(Method method, Class targetClass)这里可以根据参数打上条件断点进行调试分析调用栈,targetClass就是目标class …一系列调用
  • 最终SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)
@Override
publicTransactionAttributeparseTransactionAnnotation(AnnotatedElementae){
//这里就是分析Method是否被@Transactional注解标注,有的话,不用说BeanFactoryTransactionAttributeSourceAdvisor适配当前bean,进行代理,并且注入切点
//BeanFactoryTransactionAttributeSourceAdvisor
AnnotationAttributesattributes=AnnotatedElementUtils.getMergedAnnotationAttributes(ae,Transactional.class);
if(attributes!=null){
returnparseTransactionAnnotation(attributes);
}
else{
returnnull;
}
}

上面就是判断是否需要根据@Transactional进行代理对象创建的判断过程。@Transactional的作用一个就是标识方法需要被代理,一个就是携带事务管理需要的一些属性信息。

动态代理逻辑实现

【aop实现原理分析】中知道,aop最终的代理对象的代理方法是

  • DynamicAdvisedInterceptor#intercept

所以我们可以在这个方法断点分析代理逻辑。往期的面试题,点击查看

@Override
publicObjectintercept(Objectproxy,Methodmethod,Object[]args,MethodProxymethodProxy)throwsThrowable{
ObjectoldProxy=null;
booleansetProxyContext=false;
ClasstargetClass=null;
Objecttarget=null;
try{
if(this.advised.exposeProxy){
//Makeinvocationavailableifnecessary.
oldProxy=AopContext.setCurrentProxy(proxy);
setProxyContext=true;
}
//Maybenull.Getaslateaspossibletominimizethetimewe
//"own"thetarget,incaseitcomesfromapool...
target=getTarget();
if(target!=null){
targetClass=target.getClass();
}
//follow
Listchain=this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);
ObjectretVal;
//CheckwhetherweonlyhaveoneInvokerInterceptor:thatis,
//norealadvice,butjustreflectiveinvocationofthetarget.
if(chain.isEmpty()&&Modifier.isPublic(method.getModifiers())){
//WecanskipcreatingaMethodInvocation:justinvokethetargetdirectly.
//NotethatthefinalinvokermustbeanInvokerInterceptor,soweknow
//itdoesnothingbutareflectiveoperationonthetarget,andnohot
//swappingorfancyproxying.
Object[]argsToUse=AopProxyUtils.adaptArgumentsIfNecessary(method,args);
retVal=methodProxy.invoke(target,argsToUse);
}
else{
//Weneedtocreateamethodinvocation...
retVal=newCglibMethodInvocation(proxy,target,method,args,targetClass,chain,methodProxy).proceed();
}
retVal=processReturnType(proxy,target,method,retVal);
returnretVal;
}
finally{
if(target!=null){
releaseTarget(target);
}
if(setProxyContext){
//Restoreoldproxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

		

通过分析List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)返回的是TransactionInterceptor,利用TransactionInterceptor是如何实现代理逻辑调用的?

跟踪new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

发现最终是调用TransactionInterceptor#invoke方法,并且把CglibMethodInvocation注入到invoke方法中,从上面可以看到CglibMethodInvocation是包装了目标对象的方法调用的所有必须信息,因此,在TransactionInterceptor#invoke里面也是可以调用目标方法的,并且还可以实现类似@Around的逻辑,在目标方法调用前后继续注入一些其他逻辑,比如事务管理逻辑。

TransactionInterceptor–最终事务管理者

下面看代码。

  • TransactionInterceptor#invoke
@Override
publicObjectinvoke(finalMethodInvocationinvocation)throwsThrowable{
//Workoutthetargetclass:maybe{@codenull}.
//TheTransactionAttributeSourceshouldbepassedthetargetclass
//aswellasthemethod,whichmaybefromaninterface.
ClasstargetClass=(invocation.getThis()!=null?AopUtils.getTargetClass(invocation.getThis()):null);

//AdapttoTransactionAspectSupport'sinvokeWithinTransaction...
returninvokeWithinTransaction(invocation.getMethod(),targetClass,newInvocationCallback(){
@Override
publicObjectproceedWithInvocation()throwsThrowable{
returninvocation.proceed();
}
});
}

继续跟踪invokeWithinTransaction,下面的代码中其实就可以看出一些逻辑端倪,就是我们猜想的实现方式,事务管理。

protectedObjectinvokeWithinTransaction(Methodmethod,ClasstargetClass,finalInvocationCallbackinvocation)
throwsThrowable{

//Ifthetransactionattributeisnull,themethodisnon-transactional.
finalTransactionAttributetxAttr=getTransactionAttributeSource().getTransactionAttribute(method,targetClass);
finalPlatformTransactionManagertm=determineTransactionManager(txAttr);
finalStringjoinpointIdentification=methodIdentification(method,targetClass);

if(txAttr==null||!(tminstanceofCallbackPreferringPlatformTransactionManager)){
//StandardtransactiondemarcationwithgetTransactionandcommit/rollbackcalls.
//开启事务
TransactionInfotxInfo=createTransactionIfNecessary(tm,txAttr,joinpointIdentification);
ObjectretVal=null;
try{
//Thisisanaroundadvice:Invokethenextinterceptorinthechain.
//Thiswillnormallyresultinatargetobjectbeinginvoked.
//方法调用
retVal=invocation.proceedWithInvocation();
}
catch(Throwableex){
//targetinvocationexception
//回滚事务
completeTransactionAfterThrowing(txInfo,ex);
throwex;
}
finally{
cleanupTransactionInfo(txInfo);
}
//提交事务
commitTransactionAfterReturning(txInfo);
returnretVal;
}

else{
//It'saCallbackPreferringPlatformTransactionManager:passaTransactionCallbackin.
try{
Objectresult=((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr,
newTransactionCallback(){
@Override
publicObjectdoInTransaction(TransactionStatusstatus){
TransactionInfotxInfo=prepareTransactionInfo(tm,txAttr,joinpointIdentification,status);
try{
returninvocation.proceedWithInvocation();
}
catch(Throwableex){
if(txAttr.rollbackOn(ex)){
//ARuntimeException:willleadtoarollback.
if(exinstanceofRuntimeException){
throw(RuntimeException)ex;
}
else{
thrownewThrowableHolderException(ex);
}
}
else{
//Anormalreturnvalue:willleadtoacommit.
returnnewThrowableHolder(ex);
}
}
finally{
cleanupTransactionInfo(txInfo);
}
}
});

//Checkresult:ItmightindicateaThrowabletorethrow.
if(resultinstanceofThrowableHolder){
throw((ThrowableHolder)result).getThrowable();
}
else{
returnresult;
}
}
catch(ThrowableHolderExceptionex){
throwex.getCause();
}
}
}

		

总结

最终可以总结一下整个流程,跟开始的猜想对照。

来源:blog.csdn.net/qq_20597727/article/details/84868035

责任编辑:haq
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 代码
    +关注

    关注

    30

    文章

    4941

    浏览量

    73147
  • spring
    +关注

    关注

    0

    文章

    341

    浏览量

    15775

原文标题:Spring的@Transactional如何实现的(必考)

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    发布元服务配置隐私声明

    元服务必须先使用AGC的隐私声明托管服务生成自己的隐私声明,才能在版本信息页面选择到。详细内容参见配置隐私声明(元服务)和配置用户协议。 登录AppGallery Connect,点击“APP与元
    发表于 11-25 11:24

    闻泰科技关于荷兰经济部暂停行政令的声明

    》对安世下达的行政令”的声明。作为安世半导体的唯一控股股东,闻泰科技对此高度重视,现就相关事宜作出如下回应:  一、我司对荷兰经济部决定的立场 我司注意到荷兰经济大臣的上述声明是在中国商务部与荷兰经济部磋商后发表的,我司衷心感谢
    的头像 发表于 11-24 09:21 342次阅读

    一文了解3C认证自我声明制度

    一、什么是3C认证自我声明3C认证自我声明(CCCSelf-Declaration),是国家市场监督管理总局自2019年起推行的新型管理方式。它允许部分低风险产品企业不再通过第三方认证机构发证,而是
    的头像 发表于 11-11 11:58 371次阅读
    一文了解3C认证自我<b class='flag-5'>声明</b>制度

    并发丢数据深度剖析:MySQL锁机制与事务实战踩坑及解决方案

    1、理论来源于实践 现象 :于2025-08-13 21:45:35,事实逻辑表将自身的指标与维度同步到原子服务的实现时,出现同步过来的指标与维度丢失。 核心原因 :两次重复的事实逻辑表同步时间非常
    的头像 发表于 11-10 19:00 347次阅读
    并发丢数据深度剖析:MySQL锁机制与<b class='flag-5'>事务实</b>战踩坑及解决方案

    NVMe高速传输之摆脱XDMA设计28: TLP 事务处理程序的执行流程

    最小桥设备模型的每个端口的输入端对接一个 TLP事务处理程序, 该程序负责将接收到的 TLP 事务进行解析和路由转发。
    的头像 发表于 09-23 09:13 875次阅读
    NVMe高速传输之摆脱XDMA设计28: TLP <b class='flag-5'>事务</b>处理程序的执行流程

    NVMe高速传输之摆脱XDMA设计28: TLP 事务处 理程序的执行流程

    的上游端口时, 该响应类型事务需要根据事务的请求 ID字段与配置空间封装类的相关字段进行比较, 实现基于 ID 的路由; 如果对应接收端
    发表于 09-21 08:51

    Spring拦截器:你的请求休想逃过我的五指山!

    Spring框架,拦截器(Interceptor)是一种强大的机制,它允许开发者在请求处理的不同阶段插入自定义逻辑。WebApplicationContext作为Spring Web应用的上下文容器,为拦截器的配置和管理提供
    的头像 发表于 07-26 11:25 516次阅读
    <b class='flag-5'>Spring</b>拦截器:你的请求休想逃过我的五指山!

    如何将一个FA模型开发的声明范式应用切换到Stage模型

    模型切换概述 本文介绍如何将一个FA模型开发的声明范式应用切换到Stage模型,您需要完成如下动作: 工程切换:新建一个Stage模型的应用工程。 配置文件切换:config.json切换
    发表于 06-04 06:22

    白皮书:在HMI应用实现高精度电容触摸传感器

    在HMI 应用实现高精度电容触摸传感器
    的头像 发表于 03-17 16:46 1774次阅读
    白皮书:在HMI应用<b class='flag-5'>中</b><b class='flag-5'>实现</b>高精度电容<b class='flag-5'>式</b>触摸传感器

    声明资源管理方法

    1、管理k8s核心资源的三种基础方法 陈述管理方法:主要依赖命令行CLI工具进行管理 声明管理方法:主要依赖统一资源配置清单(manifest)进行管理 GUI管理方法:主要依赖
    的头像 发表于 12-31 10:16 1061次阅读

    梯度科技成为AI Cloud MSP技术服务实验室首批成员单位

    近日,2024全球数字经济大会云·AI·计算国际合作论坛成功召开。会上,公布了AI Cloud MSP技术服务实验室首批成员单位,梯度科技凭借在人工智能云管理服务领域的卓越实力成为AI Cloud MSP技术服务实验室首批成员单位,展现了公司在推动AI技术服务能力持续更新
    的头像 发表于 12-18 10:07 1034次阅读

    SSM与Hibernate的整合使用

    作为Java持久化框架的代表,常被整合到SSM框架。 SSM框架简介 SSM框架是指Spring、SpringMVC和MyBatis三个框架的整合使用。Spring负责依赖注入和事务
    的头像 发表于 12-17 09:14 993次阅读

    SSM框架的性能优化技巧 SSM框架RESTful API的实现

    : 缓存可以显著提高系统的响应速度。 在SSM,可以使用Redis或Memcached等缓存技术来缓存频繁访问的数据,如数据库查询结果、用户信息等。 同时,也可以利用Spring Cache抽象层来简化
    的头像 发表于 12-17 09:10 1115次阅读

    SSM框架在Java开发的应用 如何使用SSM进行web开发

    SSM框架,即Spring、SpringMVC和MyBatis的整合,是Java Web开发中常用的技术栈。它通过分层架构,实现了视图、控制、业务逻辑和数据访问的分离,提高了代码的可维护性和可扩展性
    的头像 发表于 12-16 17:28 2129次阅读

    Spring 应用合并之路(二):峰回路转,柳暗花明

    提醒下,决定抛开 Spring Boot 内置的父子容器方案,完全自己实现父子容器。 如何加载 web 项目? 现在的难题只有一个:如何加载 web 项目?加载完成后,如何持续持有 web 项目?经过思考后,可以创建一个 boot 项目的
    的头像 发表于 12-12 11:22 1411次阅读