Spring 声明式事务源码解析
2020-12-11 16:34:25 3 举报
Spring 声明式事务源码解析
作者其他创作
大纲/内容
AnnotationTransactionAttributeSource根据当前Bean 所有的方法pay 方法-- 接口pay@Transactional -- 父类pay类----接口@Transactional --父类
获得连接点标识符joinpointIdentification,之前设置descriptor,就是事务注解的匹配点
通知的大致两种转换方式:1.通过适配器2.advice本身实现了Intercepter
设置ConnectionHolder
Conection.setAutoCommit(false)开启
传播行为NEVER
createBean
封装成对象
创建一个事务状态DefaultTransactionStatus
readOnly
融入原事务
原有值暂时放进“暂停资源持有器”
doCreateBean
完整类名 数组
绑定数据源和ConnectionHolder到同步器上
方法
NOT_SUPPORTED 它挂起事务,自己不开启事务
1
解析出来就是这个
实现
挂起
符合
advise 增强代码,处理事务pointcut 匹配Bean是否符合创建动态代理资格
设置ProxyTargetClass就会用cglib动态代理,如果没有设置,并且有接口就会用jdk动态代理createProxy
第四步:事务调用(简略理解版,后面有详细版)
不代理equals方法不代理hashCode方法不代理DecoratingProxy不代理Advised
传播行为PROPAGATION_MANDATORY
没有
第三步:事务创建动态代理详细流程
传播行为PROPAGATION_REQUIRED 或PROPAGATION_REQUIRES_NEW 或PROPAGATION_NESTED
如果在配置类同时使用了@EnableTransactionManagement@EnableAspectJAutoProxyAOP对应的优先级会高
NESTED
获取一个数据库Connection,封装到ConnectionHolder中
第一次父事务肯定是不存在N
try{
加入事务的描述属性中
0
精筛
拿到所有之前解析到的advisors
其实就是将外层事务信息全部缓存在TransactionSynchronizationManager中然后干掉了原来事务的connectionHolder,变成了个空事务
传播行为REQUIRES_NEW
挂起已经存在的事务suspend
invocation.proceedWithInvocation()挂起:暂存嵌套事务作为顶层事务顶层事务的信息暂存开启新的事务
@EnableTransactionManagement开启事务
创建一个事务
根据当前类的方法解析@Transactional
doBeginConnectioncon.setAutoCommit(false); 开启事务
外层事务
Y
JdkDynamicAopProxy#invoke
获取当前的拦截器++currentInterceptorIndex
调用被代理的方法
一般情况不会到这里来。来了也白来,因为实现类已经把接口给掏空解析完了
找到了
创建“空”事务:没有实际的事务,因为后续可能要同步
转换效果
责任链调用实例List<Advise - intercepter>ReflectiveMethodInvocation.proceed()
N
DefaultAdvisorAdapterRegistry#getInterceptors
TransactionInterceptor#invoke
isolationLevel
隔离基本是null,所以默认使用数据库的隔离级别
根据事务传播属性
DataSourceTransactionManager#doBegin
getBean(\"aopBeanName\")获得aop代理的bean
置空
初筛
根据当前接口IPayService解析@Transactional
获得事务管理器PlatformTransactionManager,配置类中的,里面包含了数据源
name
解析注解
这个挂起不是大家所认知的线程挂起,其他线程等待,这里的挂起并不会阻塞其他子线程。挂起:其实就是将 嵌套事务设置为主事务,等回滚或提交后再设置回去。将主事务的信息暂时存放到另一个地方等嵌套的事务执行完了再放回去。不同线程哪怕是嵌套事务在内也不会融合,因为事务的信息是存在ThreadLocal
假设当前匹配方法是抽象方法将获得最终实现方法,所以无论是接口还是实现类都会根据实现去匹配,所以用接口匹配基本没什么用
null
AbstractAutoProxyCreator#postProcessBeforeInstantiation
Connection
createSavepoint创建一个回滚点:connection.setSavepoint(\"\")
TransactionManagementConfigurationSelector@Import —— ImportSelector
add();调用add方法
AspectJAwareAdvisorAutoProxyCreator#shouldSkip
空事务
直接调用
InfrastructureAdvisorAutoProxyCreator处理事务的BeanPostProcessorAnnotationAwareAspectJAutoProxyCreator
嵌套事务
通过getTransactionAttributeSource看是否有@Transactional注解
开启新事务
当前类或元素上是否有@Transactional
设置事务的名称
根据事务切点匹配器匹配命中的方法TransactionAttributeSourcePointcut#matches
此图请结合《AOP-创建动态代理》图一起看
ReflectiveMethodInvocation.proceed
matches
是否存在
}
解析advisor与AOP切面解析步骤一致,这里就省略了
1.去父类上找2.去接口上找
TransactionInterceptor#invokeWithinTransaction
computeTransactionAttribute
获得TransactionAttribute,之前解析的。里面包含类事务属性
全部转化为拦截器通过责任链模式调用
这里设置完就说明事务已经存在了
其实就是获取@Bean配置的数据
事务同步管理器TransactionSynchronizationManager
0--advise
wasActive
return true配对成功!
获得TransactionAttributeSource
BeanFactoryTransactionAttributeSourceAdvisor
doBegin和原来的一样的
NOT_SUPPORTED
根据当前类解析@Transactional
获得最终的实现方法
外层
在commit或rollback时resume回去
初始化后调用BeanPostProcessor.postProcessAfterInitialization
如果转换不了空
return prepareTransactionInfo(事务状态、属性、名称)new TransactionInfo
是否超时
N其他几种事务都不需要开启事务
非嵌套事务:第一次ConnectionHolder是空的,所以肯定不存在事务,ConnectionHolder会在后续的doBegin中设置嵌套事务:第一次ConnectionHolder已存在说明是嵌套事务
缓存有直接返回
CGLIB
isExistingTransaction是否存在事务
1.去侨接方法上找2.去接口对应的方法上找3.去父类对应的方法上找
createTransactionIfNecessary
当前方法是否是接口
return trueY
invocation.proceedWithInvocation()融合:嵌套事务自己不提交,由顶层事务统一提交嵌套事务
调用基于JDK动态代理
List advisors缓存
挂起的事务SuspendedResourcesHolder
2. advice 本身实现了Intercepter比如 AspectJAfterThrowingAdvice
ProxyTransactionManagementConfiguration配置类
使用@EnableAspectJAutoProxy(exposeProxy = true)
AspectJAwareAdvisorAutoProxyCreator> 继承AbstractAdvisorAutoProxyCreator > 继承AbstractAutoProxyCreator
操作数据库
类
类还是方法
将事务激活状态、隔离级别、是否只读、事务名称、事务激活 绑定到TransactionSynchronizationManager
currentInterceptorIndex=-1
回滚completeTransactionAfterThrowing
从threadLocal中获取
AutoProxyRegistrar@Import—ImportBeanDefinitionRegistrar
@Import
缓存当前方法是否解析过
递归出口:调用到了最后一个拦截器
调用动态代理类的invoke方法
作者:一角钱技术(公众号:org_yijiaoqian)内容:Spring 声明式事务源码解析
开启一个新事务
执行方法pay
matchestrue
con.setAutoCommit(false);
BeanFactoryTransactionAttributeSourceAdvisor——advisortransactionInterceptor——adviseAnnotationTransactionAttributeSource解析@Transactional
ReflectiveMethodInvocation#proceed
事务的创建动态代理与AOP步骤基本一致,前面的一些步骤这里就省略了
存在
设置设置ReadOnly和事务隔离级别
获取事务状态TransactionStatusPlatformTransactionManager.getTransaction
待本事务回滚或提交后再放回“事务同步管理器”
拿到之前解析的事务属性createTransactionIfNecessary开启事务con.setAutoCommit(false);try { 责任链递归 具体方法}catch() { 回滚 rollback}commit()
}\t\t\tcatch (Throwable ex) {
根据当前接口的方法(pay)解析@Transactional
TransactionInterceptor
JDK
AnnotationTransactionAttributeSource#getTransactionAttribute
获取一个事务对象(关键看有没有ConnectionHodler)
判断当前索引是不是最后一个,如果是直接调用具体方法
1、3 是通过MethodIntercepoter直接转换2、4 是通过适配器转换的
下次在doGetTransaction就可以获取到
第四步:事务代理类的调用详细流程
回滚commitTransactionAfterReturning(txInfo);
抛出异常
第三步:事务创建动态代理(简略理解版,后面有详细版)
searchWithFindSemantics
TransactionSynchronizationManager容器ThreadLocalresourcesConnection
1. 适配的advice
当获得被代理的bean时实际获取的时动态代理对象
加入缓存
解析exposeProxy属性
第二步:解析advisor
存在则证明是嵌套事务Y
第一步:开启事务
没有就转换
TransactionSynchronizationManager容器ThreadLocalresourcesConnectionHodler = nullreadonly...
暂停资源持有器SuspendedResourcesHolder
chain.isEmpty()
getInterceptorsAndDynamicInterceptionAdvice
缓存value
递归
最终
PointCut
0 条评论
下一页