前言
这里, 是这周的时候, 恰好似乎是 遇到了一些事务相关的东西, 因此 想周末的时候, 有一个简单的了解
其实主要是 一位同事大哥, 在看这个问题, 抛出了一个问题 [XXServiceImpl.add 方法上面有@Transactional 注解声明事务, 以及相关的一些配置, 然后 add 方法里面调用一个add0, 然后add0抛出了异常的话, add0里面的sql业务, 和add方法在add0之前的sql业务 会回滚吗] , 然后 另外一位同事去写了一个 demo, 来验证这个问题, 然后 结果并非第一位同事大哥所想那样, 然后 我突然也想到, 对于这个问题, 我也不是很明晰, 然后 第二天也洗了一下demo, 然后 更了一下demo, 但是 毕竟时间有限, 因此 追踪留到了周末
周末的饿时候, 本来还有一件非常重要的事情的, 但是 原来真是一直都想错了, 这件事情就不用了, 不过 也好, 有些东西终于明确了,因此, 就把时间 花在了这上面, 首先 周六的时候, 跟了一下 spring 容器初始化的流程, 呵呵, 这一次的追踪, 可是比 两年之前第一次追踪的饿时候轻松多了啊, 呵呵 或许是那时候 太注重细节了, 然而 现在有有点不求甚解
Get Started
然后, 这里 就进入主题吧, 首先说明一下, 这里 仅仅是一个最简单的demo, 所以 可能流程中, 会忽略很多东西, 因此 会有很多不完善的地方然后 这个过程中还会忽略很多细节, 看代码的过程中稍微比较无味的一些过程[不求甚解]
首先介绍一下环境 : jdk1.7.40 + spring-* 4.2.5.RELEASE
上基本的配置, 代码
1. 数据源, txManqager, tx:annotation-driven 的配置
2. 测试代码
在 spring 解析改配置的时候, 会创建spring 事务处理相关的一些对象 : [创建 InfrastructureAdvisorAutoProxyCreator, BeanFactoryTransactionAttributeSourceAdvisor, TransactionInterceptor, AnnotationTransactionAttributeSource]
相关部分, 可以参见 BeanDefinitionParserDelegate. parseCustomElement(Element ele, BeanDefinition containingBd)
----AnnotationDrivenBeanDefinitionParser. parse(Element element, ParserContext parserContext)
----AopAutoProxyConfigurer. configureAutoProxyCreator(Element element, ParserContext parserContext)
然后 之后是, 容器实例化单例对象 Controller, 然后 Controller 依赖于UserService, 然后先加载UserService的实例 UserServiceImpl
AbstractAutowireCapableBeanFactory. initializeBean, 这个方法还是比较重要, 调用 BeanPostProcessor 的before, after两个回调[@PostConstruct, @PreDestroy 是被CommonAnnotationBeanPostProcessor关注的两个注解, 也是这里调用的], 调用afterPropertiesSet, init-method
在 applyBeanPostProcessorsAfterInitialization 的时候, 有一个 BeanPostProcessor 对于我们这里比较重要 : InfrastructureAdvisorAutoProxyCreator
这个类的 后置处理, 用于创建代理, 参见 AbstractAutoProxyCreator. postProcessAfterInitialization
----AbstractAutoProxyCreator.wrapIfNecessary : 获取关注当前 bean 的所有 Advisor 以及默认的公共的 Advisor, 然后 创建代理
--------DefaultAopProxyFactory. createAopProxy : 根据策略选择 代理的方式, 优先选择 JdkDynamicAopProxy[这里我们的 UserServiceImpl 选用的而是JdkDynamicAopProxy]
AbstractAutowireCapableBeanFactory. initializeBean
当前beanFactory所有的BeanPostProcessor
关注UserService 的所有 Advisor
调用被代理的方法[userService.txAdd]的时候, 处理的业务逻辑
JdkDynamicAopProxy. invoke
----AdviseSupport. getInterceptorsAndDynamicInterceptionAdvice : 遍历关注当前 bean 的所有Advisor, 获取关注当前方法的 interceptor
--------这里我们的 关注当前bean的 advisor 只有一个 BeanFactoryTransactionAttributeSourceAdvisor[上面 "tx:annotation-driven" 注册的 advisor]
--------这里, 检测 当前Advisor 是否关注当前方法的流程, 相见如下代码[检测Transactional注解, 实现方法 -> 实现类 -> 代理方法 -> 代理类]
--------
--------结果, 拿到一个 TransactionInterceptor
----ReflectiveMethodInvocation. proceed : 责任链模式, 处理所有的 MethodIntereptor, InterceptorAndDynamicMethodMatcher[不匹配当前方法, 则忽略当前InterceptorAndDynamicMethodMatcher]
检测 BeanFactoryTransactionAttributeSourceAdvisor 是否关注当前方法
然后, 下面的这个 Intercpetor 就是我们这里业务上关注的重点了
TransactionInterceptor. invokeWithinTransaction : 创建连接, 配置连接, 标记事务同步, 处理业务, 如果 发生异常, 或者标记回滚, 进行回滚操作, 否则, 提交事务
----createTransactionIfNecessary : 获取连接, 标记连接和事务同步[ConnectionHolder. synchronizedWithTransaction], 配置当前连接的相关属性[isolationLevel, readOnly, autoCommit, timeout 等等], 绑定当前线程的 dataSource -> 当前连接的映射
--------初始化当前事务的配置[isolationLevel, readOnly, txName, 同步Listener], push transactionInfoHolder
----InvocationCallback. proceedWithInvocation : 处理责任链上面剩余的 Interceptor, 以及业务逻辑
----completeTransactionAfterThrowing : 判断给定的异常, 是否需要回滚, 回滚, 否则 提交事务
--------DataSourceTransactionManager. doRollback : 事务回滚
----cleanupTransactionInfo : pop transactionInfoHolder
----commitTransactionAfterReturning : 如果需要回滚[localRollyBack, gloablRollback], 则进行回滚操作, 否则 提交事务, 重置连接, 重置当前线程的相关信息
--------AbstractPlatformTransactionManager. processCommit : 通知事务监听的几个事件[beforeCommit, triggerBeforeCompletion, afterCommit, afterCompletion]
------------DataSourceTransactionManager. doCommit 提交事务
----提交 或者回滚了之后, 重置当前线程的事务同步相关资源, 重置连接的属性, 释放连接
以上, 是外围的框架的相关的业务, 接下来, 我们看下 业务代码消费连接的情况?
----DataSourceUtils. doGetConnection : 如果当前线程开启了事务同步, 获取dataSource对应的 ConnectionHolder
--------如果从 TransactionSynchronizationManager. resources 拿到了ConnectionHolder[表示上下文开启了事务同步], 获取连接返回[如果没有连接, 新建连接]
--------否则 从数据源拿连接, 如果开启了事务同步, 标记连接同步事务, 如果是新建的链接, 缓存ConnectionHolder 返回
因此, 整个流程, 大概就是 TransactionInterceptor. createTransactionIfNecessary 中创建了连接, 并做了事务相关的配置
然后 UserServiceImpl 中使用连接处理业务, 10条 insert 语句, 然后 第十条的时候抛出了 RuntimeException
然后 TransactionInterceptor. invokeWithinTransaction 检测到 异常, 并且该异常需要 回滚, 然后 completeTransactionAfterThrowing 回滚操作
最后 TransactionInterceptor 释放资源, 重置当前线程同步相关占用的资源
完