当前位置: 首页 > 后端技术 > Java

面试官:@Transactional注解是如何实现的?

时间:2023-04-02 09:34:56 Java

@Transactional注解介绍@Transactional是spring中声明式事务管理的一种注解配置方式。相信大家都知道这个注解的作用。@Transactional注解可以帮助我们通过aop管理开启、提交或回滚事务的操作。通过@Transactional注解,spring可以为我们管理事务,省去重复的事务管理逻辑,减少业务代码的侵入,让我们的开发人员可以专注于业务层面的开发。我们知道@Transactional原理的实现是基于springaop的,也是动态代理方式的实现。通过阅读源码,我们总结出以下几个步骤来理解spring在实践中是如何使用aop实现@Transactional的功能的。首先,如果你对spring中的aop实现原理有所了解,你应该知道,要想代理一个方法,就必须定义一个切入点。在@Transactional的实现中,也是如此。Spring以@Transactional注解为我们定义了一个切入点作为植入点,这样我们就可以知道@Transactional注解标记的方法需要被代理。定义完切面后,在springbean的初始化过程中,需要对实例化的bean进行代理,生成代理对象。在生成代理对象的代理逻辑中,在进行方法调用时,需要先获取切面逻辑。@Transactional注解的切面逻辑与@Around类似,spring中也实现了类似的代理逻辑。@Transactional的作用是根据以上原理推测出来的。下面简单介绍一下验证的各个步骤的源码。第一个是@Transactional,用于定义代理植入点。我们知道代理对象是通过BeanPostProcessor实现类AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInstantiation方法创建的。如果需要代理,那么在这个方法中会返回一个代理对象给容器,植入点也是在这个方法中判断的。下面开始分析。配置注解驱动的事务管理后,spring会在ioc容器中创建一个BeanFactoryTransactionAttributeSourceAdvisor实例。这个实例可以看作是一个切点,决定一个bean在初始化时是否需要创建代理对象。需要验证BeanFactoryTransactionAttributeSourceAdvisor是否是这个bean的切入点。如果是这样,您需要创建一个代理对象并将BeanFactoryTransactionAttributeSourceAdvisor实例注入到代理对象中。在上一篇文章中我们知道在AopUtils#findAdvisorsThatCanApply中可以判断aspect是否适用于当前bean。我们可以分析这个地方的调用栈,AopUtils#findAdvisorsThatCanApply调用一致,最后通过下面的代码判断切面是否适用。AbstractFallbackTransactionAttributeSource#computeTransactionAttribute(Methodmethod,ClasstargetClass)这里可以根据参数设置条件断点调试分析调用栈,targetClass就是目标类...一系列的调用最后SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)@OverridepublicTransactionAttributeparseTransactionAnnotation(AnnotatedElementae){//这里是分析Method是否被注解了@Transactional注解。如果是,不用说BeanFactoryTransactionAttributeSourceAdvisor适配当前bean,进行代理,注入切入点如果(属性!=null){返回parseTransactionAnnotation(属性);}else{返回空值;}}以上就是根据@Transactional判断是否创建代理对象的过程。@Transactional的一个作用是标识需要代理的方法,另一个是携带一些事务管理需要的属性信息。推荐一个SpringBoot基础教程和实例:https://github.com/javastacks...动态代理逻辑实现【aop实现原理解析】我们知道aop的最终代理对象的代理方法是DynamicAdvisedInterceptor#intercept所以我们可以在此方法断点处分析代理逻辑。@OverridepublicObjectintercept(Objectproxy,Methodmethod,Object[]args,MethodProxymethodProxy)throwsThrowable{ObjectoldProxy=null;布尔值setProxyContext=false;类targetClass=null;对象目标=空;try{if(this.advised.exposeProxy){//如有必要,使调用可用。oldProxy=AopContext.setCurrentProxy(proxy);setProxyContext=true;}//可能为空。尽可能晚地获取以减少我们//“拥有”目标的时间,以防它来自池...target=getTarget();如果(目标!=null){targetClass=target.getClass();}//遵循Listchain=this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);对象返回值;//检查我们是否只有一个InvokerInterceptor:也就是说,//没有真正的建议,而只是目标的反射调用。如果(链。isEmpty()&&Modifier.isPublic(method.getModifiers())){//我们可以跳过创建MethodInvocation:直接调用目标。//请注意,最终调用者必须是一个InvokerInterceptor,因此我们知道//它只对目标执行反射操作,没有热//交换或花哨的代理。对象[]argsToUse=AopProxyUtils.adaptArgumentsIfNecessary(方法,args);retVal=methodProxy.invoke(target,argsToUse);}else{//我们需要创建一个方法调用...retVal=newCglibMethodInvocation(proxy,target,method,args,targetClass,chain,methodProxy).proceed();}retVal=processReturnType(代理、目标、方法、retVal);返回值;}finally{if(target!=null){releaseTarget(target);}if(setProxyContext){//恢复旧代理。AopContext.setCurrentProxy(oldProxy);}}}通过分析Listchain=this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass),返回的是TransactionInterceptor,如何利用TransactionInterceptor实现代理逻辑调用?跟踪新的CglibMethodInvocation(proxy,target,method,args,targetClass,chain,methodProxy).proceed();发现终于调用了TransactionInterceptor#invoke方法,在invoke方法中注入了CglibMethodInvocation。从上面我们可以看出,CglibMethodInvocation包装了目标对象方法调用的所有必要信息。所以在TransactionInterceptor#invoke中也可以调用目标方法,实现类似@Around的逻辑,在目标方法调用前后可以注入一些其他的逻辑,比如事务管理逻辑TransactionInterceptor–Thefinaltransactionmanager看看下面的代码。TransactionInterceptor#invoke@OverridepublicObjectinvoke(finalMethodInvocationinvocation)throwsThrowable{//计算出目标类:可能是{@codenull}。//TransactionAttributeSource应该传递给目标类//以及可能来自接口的方法。ClasstargetClass=(invocation.getThis()!=null?AopUtils.getTargetClass(invocation.getThis()):null);//适配TransactionAspectSupport的invokeWithinTransaction...returninvokeWithinTransaction(invocation.getMethod(),targetClass,newInvocationCallback(){@OverridepublicObjectproceedWithInvocation()throwsThrowable{returninvocation.proceed();}});}继续跟踪invokeWithinTransaction,从下面的代码可以看出一些逻辑线索,就是我们猜测的事务管理的实现方法。protectedObjectinvokeWithinTransaction(Methodmethod,ClasstargetClass,finalInvocationCallbackinvocation)throwsThrowable{//如果事务属性为null,则该方法是非事务性的。finalTransactionAttributetxAttr=getTransactionAttributeSource().getTransactionAttribute(方法,targetClass);最终PlatformTransactionManagertm=determineTransactionManager(txAttr);finalStringjoinpointIdentification=methodIdentification(method,targetClass);if(txAttr==null||!(tminstanceofCallbackPreferringPlatformTransactionManager)){//使用getTransaction和提交/回滚调用的标准事务划分。//启动事务TransactionInfotxInfo=createTransactionIfNecessary(tm,txAttr,joinpointIdentification);对象retVal=null;try{//这是一个绕过建议:调用链中的下一个拦截器。//这通常会导致目标对象成为调用。//方法调用retVal=invocation.proceedWithInvocation();}catch(Throwableex){//目标调用异常//返回滚事务completeTransactionAfterThrowing(txInfo,ex);扔前;}最后{cleanupTransactionInfo(txInfo);}//提交事务commitTransactionAfterReturning(txInfo);返回值;}else{//这是一个CallbackPreferringPlatformTransactionManager:传入一个TransactionCallback。=prepareTransactionInfo(tm,txAttr,joinpointIdentification,status);try{returninvocation.proceedWithInvocation();}catch(Throwableex){if(txAttr.rollbackOn(ex)){//RuntimeException:将导致回滚。if(exinstanceofRuntimeException){throw(RuntimeException)ex;}else{抛出新的ThrowableHolderException(ex);}}else{//正常的返回值:将导致提交。返回新的ThrowableHolder(ex);}}最后{cleanupTransactionInfo(txInfo);}}});//检查结果:可能表示要重新抛出一个Throwable。if(resultinstanceofThrowableHolder){throw((ThrowableHolder)结果).getThrowable();}else{返回结果;}}catch(ThrowableHolderExceptionex){抛出ex.getCause();分析源码后猜测比较

最新推荐
猜你喜欢