读书笔记-《Spring技术内幕》(四)事务
前面我们依次学习了 IoC、AOP、MVC(读书笔记-《Spring技术内幕》(一)IoC容器的实现、读书笔记-《Spring技术内幕》(二)AOP的实现、读书笔记-《Spring技术内幕》(三)MVC与Web环境),已经涵盖了 Spring 最核心的内容。
今天,我们再来研究一个比较常用的组件——事务,然后这本书的读书笔记就可以完结了~
01
Spring 事务概述
按照惯例,我们先从程序员的视角出发,看看 Spring 帮我们做了什么,再学习其具体的设计与实现。
在没有使用 Spring 的 JavaWeb 项目中,是怎么实现事务的呢?请看下面的示例代码:
public void hello {
Connection conn = openConnection();
try {
conn.setAutoCommit(false);
// 业务代码
conn.commit();
} catch (SQLException e) {
conn.rollback();
} finally {
conn.setAutoCommit(true);
conn.close();
}
}
这个 Connection 我印象很深,初学时因为它学习到了第一个设计模式——单例模式,这个模式的懒汉/饿汉实现、双重检测是早期常见的面试题。(跑题了,赶紧拉回来……)
简单来说,这里的代码直接操作数据库连接,并且将事务处理代码和业务代码耦合,非常糟糕。
而在 Spring 的帮助下,我们只需要一行注解,就很优雅。
@Transactional
public void world {
// 业务代码
}
看到这种将非业务功能代码解耦出来,并通过注解(声明式)实现功能的操作,很容易猜到,其原理是通过 AOP 将事务处理的功能编织进来,本质上可以看作是一个基于 Spring IoC、AOP 的优秀应用。(注意:后面默认指代的是声明式使用,Spring 事务也可以编程式使用,其实现非常简单,不涉及框架特性,但是会耦合业务代码,本文不做讲述)
既然如此,从流程上看 Spring 事务的实现就有两个重点:
-
如何读取配置,并构造这个代理对象?
-
这个代理对象如何实现事务的创建、提交、回滚等等?
02
Spring 事务设计概览
在回答上面两个问题之前,我们先看看类层次结构。
简单概括并补充一下:
-
ProxyConfig、FactoryBean 等:为前面 IoC、AOP 模块的设计,不做赘述。
-
TransactionProxyFactoryBean:生成代理对象。
-
TransactionInterceptor:核心类,对代理方法进行拦截,将事务功能编织进来。
-
PlatformTransactionManager、AbstractPlatformTransactionManager:封装底层不同数据库对事务的实现,如生成、提交、回滚、挂起等。
-
TransactionAttribute:事务配置信息在 Spring 中的抽象。
-
TransactionInfo:事务信息抽象,包含事务和 TransactionStatus。
03
构建代理对象
构建代理对象的时序图如上所示,用文字概括一下:
-
在 IoC 容器完成 Bean 的依赖注入时,通过 initializeBean() 调用 createMainInterceptor(),创建一个 TransactionAttributePointcut,为读取 TransactionAttribute 做准备。
-
由于 AbstractSingletonProxyFactoryBean 实现了 InitializingBean 接口,在 afterPropertiesSet() 中会实例化 ProxyFactory,设置通知、目标对象,最终返回代理对象。
-
在构建好代理对象后,调用代理方法时便会调用相应的 TransactionInterceptor,匹配对应的配置。(举个例子的话可以看看 NameMatchTransactionAttributeSource,其通过成员变量 nameMap 的维护来实现名称匹配)
04
处理事务
构建好代理对象后,对原方法的调用就会被拦截,也就是进入 TransactionInterceptor 的 invoke()。其会依次获取事务处理配置、PlatformTransactionManager,并交由这个具体的处理器来实现事务的创建、提交、回滚等等。
这里我们就以事务的创建为例,看看 TransactionAspectSupport 的 createTransactionIfNecessary 方法的时序图。
这里就两点可以留意下:
-
针对不同的事务传播机制,源码里有各种条件分支。(不过在实际工作中,我还没使用过非默认的传播机制,一般是通过 MQ 来保障最终一致性)
-
bindToThread() 是通过 TransactionAspectSupport 的成员变量 ThreadLocal<TransactionInfo> transactionInfoHolder 实现,其也体现了事务的隔离性。
至此,我们只需再进一步就可抵达终点了。
前面的类层次结构图有提到 AbstractPlatformTransactionManager,其定义了事务的生成、提交、回滚、挂起,对于不同的数据库有不同的实现。
以 DataSourceTransactionManager 为例,点开它的源码一看,我们就会发现非常眼熟。它就和一开始我们写的示例代码类似,直接操作 Connection,打印日志等等。
原文链接:读书笔记-《Spring技术内幕》(四)事务
原创不易,点个关注不迷路哟,谢谢~
文章推荐:
- 如何提高核心竞争力
- 读书笔记-《当下的力量》
- 读书笔记-《写给大家看的设计书》
- 赛博朋克2077玩后感
- 程序员工作中常见问题,你遇到过几个?
- 如何设计离线跑批系统
- 读书笔记-《人人都是产品经理》
- 如何养成好习惯
- 读书笔记-《最好的告别》