spring整套源码系列之【spring声明式事务源码】
2024-04-10 18:45:29 0 举报
spring整套源码系列之【spring声明式事务源码】
作者其他创作
大纲/内容
NEVER
实例化
挂起当前事务操作suspendedResources = doSuspend(transaction);
return new String[] {\t\t\t\t\t\tTransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
如果存在exposeProxy = true配置把我们的代理对象暴露到线程变量中
这里是能进来的,我们在处理外部事务的时候是有把synchronizations存到线程变量中
在springioc容器中加载bean定义的时候会回调我们的selectImports方法, 方法的返回值是我们需要导入类的全类名路径.然后这个类就会被加载到容器中
创建bean定义
返回这两个类的权限名,接着Import会创建两个bean定义
//获取到我们的目标对象\t\tTargetSource targetSource = this.advised.targetSource;
单例池
这个其实不重要,代表着使用AspectJ的方式,我们通常不会这么做
获取我们目标对象的classClass<?> targetClass = (target != null ? target.getClass() : null);
//尝试获取一个事务对象\t\tObject transaction = doGetTransaction();
NOT_SUPPORTED
拦截器链为空则直接调用目标方法,不为空则加强执行
是:开启新事务
#DataSourceTransactionManager
//获取当前挂起的事务集合,我们第一个嵌套事务进来当然为空\t\t\tList<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
编程式处理
不开启新的事务
当前的事务属性状态是PROPAGATION_REQUIRES_NEW表示需要新开启一个事务状态
case ASPECTJ
这是if里面的操作
同样的也是只看事务的关键源码,因为之前aop看过了
配置类ProxyTransactionManagementConfiguration
获取我们的代理对象的class属性\t\tClass<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
创建这个的时候pointcut默认
属性赋值
这里跟aop代理一模一样,所以就不看了,同样是判断是用jdk代理还是cglib代理,最终都是生成一个代理对象
else if
//挂起存在的事物,并获取外部事务的信息 Object suspendedResources = suspend(transaction);
//创建一个数据源事务对象\t\tDataSourceTransactionObject txObject = new DataSourceTransactionObject();
调用
先清空TransactionSynchronizationManager所有缓存信息
return true
try
解析aop跟事务postProcessBeforeInitialization(..)#AbstractAutoProxyCreator
否
第一次调用bean后置处理器用来解析切面
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
InstantiationAwareBeanPostProcessor
@Bean
不包含
//挂起已经存在的事物\t\t\tSuspendedResourcesHolder suspendedResources = suspend(transaction);
保存我们的advisorList,这里只关心BeanFactoryTransactionAttributeSourceAdvisor
AutoProxyRegistrar
有
//为事物设置一个回退点\t\t\t\tstatus.createAndHoldSavepoint();
这里我案例中配置的事务管理器对象是这个类型,所以执行这个类的方法
初始化
put
invocation::proceed是个钩子,代表执行invocation对象的proceed方法
matches(Class<?> clazz)#TransactionAttributeSourcePointcut
是
SUPPORTS
同样的主要是分析事务的源码,详细在aop源码中有分析了
融合到外部事务中
不存在
else
包含
//清空我们的线程变量中transactionInfo的值\t\t\t\tcleanupTransactionInfo(txInfo);
不是
创建了一个advisor beanBeanFactoryTransactionAttributeSourceAdvisor
//提交事务\t\t\tcommitTransactionAfterReturning(txInfo);
抛出异常
return status;
//获取出只读事务的名称\t\t\t\tboolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
设置事务超时时间\t\t\tint timeout = determineTimeout(definition);
return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
声明式事务处理
类似pointcut
spring的事务传播行为
获取我们@EnableTransactionManagement注解为我们容器中导入的ProxyTransactionManagementConfiguration 配置类中的TransactionAttributeSource对象TransactionAttributeSource tas = getTransactionAttributeSource();
@EnableTransactionManagement注册InfrastructureAdvisorAutoProxyCreator、@EnableAspectJAutoProxy注册AnnotationAwareAspectJAutoProxyCreator
cglib代理产生的代理对象ObjenesisCglibAopProxy
return
MANDATORY
挂起外部事务,创建新的事务
获取拦截链中的方法,并且currentInterceptorIndex提前加1 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
执行目标方法return invokeJoinpoint();
这里挂起的是嵌套自己的事务对象,别混了
jdk动态代理对象JdkDynamicAopProxy
这里就都不进去分析了,前面aop解析源码已经看过了,也就是找当前bean定义中有没有实现了Advisor的,显然我们已经有了一个了
存在
NESTED
这里是作为调用链出口的判断,每执行完一次currentInterceptorIndex 都会加1,默认为-1this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1
执行目标方法并增强
invoke(MethodInvocation invocation)#TransactionInterceptor
//转为PointcutAdvisor类型\t\t\tPointcutAdvisor pca = (PointcutAdvisor) advisor;
TransactionSynchronizationManager类的静态变量
//调用钩子函数进行回调目标方法\t\t\t\tretVal = invocation.proceedWithInvocation();
//解绑TransactionSynchronizationManager的数据库dataSource,并返回dataSource,在嵌套事务中这里返回的就是外部事务保存的dataSource\t\treturn TransactionSynchronizationManager.unbindResource(obtainDataSource());
找到所有的所实现的接口的class对象然后循环
invoke执行(自然里面也会先getBean)
ImportSelectorselectImports(AdviceMode adviceMode)
从单例池中拿到的其实是代理对象
入口3
创建好bean
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED
这里面有个判断annotationName.startsWith(\"java.\")的意思是java的@Transactional也可以
//返回事务对象\t\treturn txObject;
把事务的数据库连接对象制空transaction.setConnectionHolder((ConnectionHolder)null);
开启新的事务
ImportBeanDefinitionRegistrarregisterBeanDefinitions()
不代理equals方法;不代理hashCode方法;不代理执行的class对象是DecoratingProxy;不代理advised
getBean()
调用方法其实调用的是代理对象的方法
这里就是将TransactionSynchronizationManager的线程变量先拿出来然后清空,也就是拿到了外部事务的线程属性
这里就是执行了钩子【invocation::proceed】函数最终回到了ReflectiveMethodInvocation.proceed(),然后因为没有advisor了所以会执行目标方法
创建了AnnotationTransactionAttributeSource用来解析事务注解,可以理解成pointcut,但是它又不是一个pointcut
//回滚\t\t\t\t\ttxInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
获取我们的目标对象\t\t\ttarget = targetSource.getTarget();
postProcessAfterInitialization()
创建一个adviceTransactionInterceptor
从bean定义中找有没有实现了Advisor的bean定义 findCandidateAdvisors();
finally
doCreateBean()
判断传播行为是否为NESTED,如果是需要融合到外部事务
通过数据源获取一个数据库连接对象 Connection newCon = obtainDataSource().getConnection();
判断事务对象有没有数据库连接持有器!txObject.hasConnectionHolder()
case PROXY
catch (Throwable ex)
开启事务
不为空
//清空线程变量的事务的名称 TransactionSynchronizationManager.setCurrentTransactionName(null);
匹配方法跟匹配类共用的一个方法
返回事务代理对象
//获取线程变量的隔离级别 Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
//找到ioc容器中候选的通知 List<Advisor> candidateAdvisors = findCandidateAdvisors();
返回创建好的代理对象return proxy;
进来这里说明外层没有事务
查看是否已经包含了这个name的bean定义registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)
就是我们使用@Bean配置的事务管理器对象
advice
循环所有方法
//调用执行\t\t\t\tretVal = invocation.proceed();
REQUIRED(默认)
//获取已存在的事物的名称\t\t\t\tString name = TransactionSynchronizationManager.getCurrentTransactionName();
入口1
挂起外部事务
REQUIRES_NEW
判断抛出的异常是不是我们需要回滚的异常txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)
外部存在事务
循环所有class
//把事务信息对象绑定到当前线程变量中 txInfo.bindToThread();
不管是哪个他们实现方法都是一样的,都是继承了AbstractAutoProxyCreator的方法(包括实例化前解析方法跟初始化后处理方法)
创建一个新事务
每次都是新事务对象,也就是当前事务(嵌套事务进来这里也是重新创建的事务对象)
判断是声明式事务还是编程式事务txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)
在这个里面如果只是加了@EnableTransactionManagement注解的话注册的是InfrastructureAdvisorAutoProxyCreator.class,如果同时加了@EnableAspectJAutoProxy注解的话,注册的是AnnotationAwareAspectJAutoProxyCreator.class(替换成这个)。因为他们的name是一样的。因为本身他们的方法实现都是一样的,比如在解析的时候都是来自AbstractAutoProxyCreator.postProcessBeforeInitialization(...)方法,spring当然不会重复注册两个
解析@Import
外部不存在事务
//提交事务\t\t\t\t\ttxInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
通过切点获取到一个方法匹配器对象MethodMatcher methodMatcher = pc.getMethodMatcher();
入口2
getBean
若当前的事务属性式 PROPAGATION_MANDATORY 表示必须运行在事务中,若当前没有事务就抛出异常,由于isExistingTransaction(transaction)跳过了这里,说明当前是不存在事务的,那么就会抛出异常
//获取我们的事务属源对象\t\tTransactionAttributeSource tas = getTransactionAttributeSource();
这里挺重要的,当嵌套事务的时候,因为已经存在一个事务,就会进入判断
粗筛:看类上有没有注解!pc.getClassFilter().matches(targetClass)
postProcessBeforeInstantiation()
创建事务代理对象
没有
//清空线程变量的隔离级别\t\t\t\tTransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
这里在意的是前面创建好的事务的advisor
找到class中所有的方法然后循环,只要有一个带了Transactional注解说明需要代理
这里会有个循环候选advisorList
这里事务相关的advisor只有一个,也就是前面创建的,不像我们aop中有很多的通知,每个通知都有一个advisor,在这里只有一个通知就能解决了,无非就是在方法前方法后作相应的事务逻辑
这里地方的源码在aop中都已经有看过了,这里就列事务的关键代码分析就行了
判断是不是已经存在了事务对象isExistingTransaction(transaction)
获取一个事务状态tm.getTransaction(txAttr);#AbstractPlatformTransactionManager
检查事务设置的超时时间,超时就抛出异常,不设置永远不会超时
//清空线程变量的只读事务的名称\t\t\t\tTransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
BeanPostProcessor
设置事务激活\t\t\ttxObject.getConnectionHolder().setTransactionActive(true);
registerBeanDefinitions#AutoProxyRegistrar
//清空线程变量的激活标志\t\t\t\tTransactionSynchronizationManager.setActualTransactionActive(false);
关闭自动提交con.setAutoCommit(false);
解析配置类
//强制转化事务对象 DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
然后就把拿到的外部事务信息用一个SuspendedResourcesHolder对象封装起来
//获取我们配置的事务管理器对象 final PlatformTransactionManager tm = determineTransactionManager(txAttr);
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
此时已存在一个advisor的bean定义
return eligibleAdvisors;
事务传播行为类型
没
也就是在import里面会执行到
创建事务代理对象postProcessAfterInitialization()#AbstractAutoProxyCreator
@EnableTransactionManagement
TransactionManagementConfigurationSelector
这个方法就是为了嵌套事务写的,嵌套事务指的是事务方法里面调用另外一个事务方法
selectImports(AdviceMode adviceMode)#TransactionManagementConfigurationSelector
注册或替换成AOP的AnnotationAwareAspectJAutoProxyCreator
//获取线程变量的激活标志\t\t\t\tboolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
0 条评论
下一页