Spring源码系列文章
Spring源码解析(一):环境搭建
Spring源码解析(二):bean容器的创建、默认后置处理器、扫描包路径bean
Spring源码解析(三):bean容器的刷新
Spring源码解析(四):单例bean的创建流程
Spring源码解析(五):循环依赖
Spring源码解析(六):bean工厂后置处理器ConfigurationClassPostProcessor
Spring源码解析(七):bean后置处理器AutowiredAnnotationBeanPostProcessor
Spring源码解析(八):bean后置处理器CommonAnnotationBeanPostProcessor
Spring源码解析(九):AOP源码之@Aspect所有相关注解解析
Spring源码解析(十):spring整合mybatis源码
Spring源码解析(十一):spring事务配置类源码
目录
- 一、编程式事务
- 1、基础使用
- 2、PlatformTransactionManager
- 3、TransactionDefinition
- 4、TransactionStatus
- 二、声明式事务注册bean
- 1、基本使用
- 2、@EnableTransactionManagement
- 3、AutoProxyRegistrar注册自动代理创建者
- 4、ProxyTransactionManagementConfiguration注册事务管理bean
- 三、创建代理对象
一、编程式事务
1、基础使用
- TransactionManager 管理事务对象
@Bean
public TransactionManager transactionManager() {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource());
return dataSourceTransactionManager;
}
- TransactionDefinition 事务的属性对象
@Bean
public TransactionDefinition transactionDefinition() {
return new DefaultTransactionDefinition();
}
- 开启事务(获取事务)、提交事务、回滚事务
// 通过事务管理器开启一个事务
TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
try {
// 完成自己的业务逻辑
}
catch (MyException ex) {
// 出现异常,进行回滚
transactionManager.rollback(transactionStatus);
throw ex;
}
// 提交事务
transactionManager.commit(transactionStatus);
2、PlatformTransactionManager
- 定义了完成一个事务必须的三个步骤:开启事务、提交事务、回滚事务
- 抽象父类AbstractPlatformTransactionManager
- 主要用作事务管理的模板
- 实现了事务的传播行为以及跟事务相关的同步管理
- 开启事务的方法就是通过一个
TransactionDefinition
来获取一个TransactionStatus
类型的对象
public interface PlatformTransactionManager extends TransactionManager {
// 开启事务
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
// 提交事务
void commit(TransactionStatus status) throws TransactionException;
// 回滚事务
void rollback(TransactionStatus status) throws TransactionException;
}
// 标记接口
public interface TransactionManager {
}
PlatformTransactionManager的实现类
AbstractPlatformTransactionManager,Spring提供的一个事务管理的基类,提供了事务管理的模板,实现了Spring事务管理的一个标准流程
- 判断当前是否已经存在一个事务
- 应用合适的事务传播行为
- 在必要的时候挂起/恢复事务
- 提交时检查事务是否被标记成为
rollback-only
- 在回滚时做适当的修改(是执行真实的回滚/还是将事务标记成
rollback-only
) - 触发注册的同步回调
AbstractPlatformTransactionManager提供了四个常见的子类,其说明如下
3、TransactionDefinition
public interface TransactionDefinition {
// 定义了7中事务的传播机制
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
// 4种隔离级别,-1代表的是使用数据库默认的隔离级别
// 比如在MySQL下,使用的就是ISOLATION_REPEATABLE_READ(可重复读)
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
// 事务的超时时间,默认不限制时间
int TIMEOUT_DEFAULT = -1;
// 提供了对上面三个属性的get方法
default int getPropagationBehavior() {
return PROPAGATION_REQUIRED;
}
default int getIsolationLevel() {
return ISOLATION_DEFAULT;
}
default int getTimeout() {
return TIMEOUT_DEFAULT;
}
// 事务是否是只读的,默认不是
default boolean isReadOnly() {
return false;
}
// 事务的名称
@Nullable
default String getName() {
return null;
}
// 返回一个只读的TransactionDefinition
// 只对属性提供了getter方法,所有属性都是接口中定义的默认值
static TransactionDefinition withDefaults() {
return StaticTransactionDefinition.INSTANCE;
}
}
- 有些是数据库层面本身就有的,例如
隔离级别、是否只读、超时时间、名称
- 也有些是Spring赋予的,例如事务的
传播机制
Spring中一共定义了7种事务的传播机制
- TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务(
默认
) - TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起
- TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起
- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常
- TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常
- TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于默认方式
TransactionDefinition默认实现类DefaultTransactionDefinition
- 为定义属性提供了默认值
public class DefaultTransactionDefinition implements TransactionDefinition{
...
// 默认的传播机制为required,没有事务新建一个事务
// 有事务的话加入当前事务
private int propagationBehavior = PROPAGATION_REQUIRED;
// 隔离级别跟数据库默认的隔离级别一直
private int isolationLevel = ISOLATION_DEFAULT;
// 默认为-1,不设置超时时间
private int timeout = TIMEOUT_DEFAULT;
// 默认不是只读的
private boolean readOnly = false;
...
}
4、TransactionStatus
- 这个接口主要用于描述Spring
事务的状态
,其继承关系如下:
TransactionExecution
,这个接口也是用于描述事务的状态
// 判断当前事务是否是一个新的事务
// 不是一个新事务的话,那么需要加入到已经存在的事务中
boolean isNewTransaction();
// 事务是否被标记成RollbackOnly
// 如果被标记成了RollbackOnly,意味着事务只能被回滚
void setRollbackOnly();
boolean isRollbackOnly();
// 是否事务完成,回滚或提交都意味着事务完成了
boolean isCompleted();
SavepointManager
,定义了管理保存点(Savepoint)的方法- 隔离级别为NESTED时就是通过设置回滚点来实现的
// 创建保存点
Object createSavepoint() throws TransactionException;
// 回滚到指定保存点
void rollbackToSavepoint(Object savepoint) throws TransactionException;
// 移除回滚点
void releaseSavepoint(Object savepoint) throws TransactionException;
TransactionStatus
,继承了上面这些接口,额外提供了两个方法
//用于判断当前事务是否设置了保存点
boolean hasSavepoint();
// 这个方法复写了父接口Flushable中的方法
// 主要用于刷新会话
// 对于Hibernate/jpa而言就是调用了其session/entityManager的flush方法
void flush();
总结:
- TransactionDefinition的主要作用是给出一份
事务属性的定义
,然后事务管理器根据给出的定义来创建事务 - TransactionStatus主要是用来描述创建后的
事务的状态
二、声明式事务注册bean
1、基本使用
- spring整合mybatis并添加事务配置和使用
@Configuration // 声明该类是核心配置类
@ComponentScan("com.xc") // 开启spring注解扫描
@MapperScan("com.xc.mapper") // MyBatis扫描Mapper接口
@EnableTransactionManagement
public class MybatisConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setPassword("root");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true");
return driverManagerDataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean() {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
return sqlSessionFactoryBean;
}
// 使用Spring中的DataSourceTransactionManager管理事务
@Bean
public DataSourceTransactionManager transactionManager() {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource());
return dataSourceTransactionManager;
}
// 执行操作
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MybatisConfig.class);
UserMapper userMapper = context.getBean(UserMapper.class);
User user = new User(200,"李四");
userMapper.insertOne(user);
}
}
- 通过开启AOP自动代理并向容器中注册事务需要的通知(
Transaction Advisor
) - 其内部也是调用了
TransactionManager
的方法 - 主要涉及到两个核心注解
@EnableTransactionManagement
@Transactional
2、@EnableTransactionManagement
- Spring事务管理的入口就是
@EnableTransactionManagement
注解 - 与之前讲过的@EnableAspectJAutoProxy很相似
- 可以选择使用jdk或cglib代理
- 都通过@Import注册bean
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
// 是否使用cglib代理,默认是jdk代理
boolean proxyTargetClass() default false;
// 使用哪种代理模式,Spring AOP还是AspectJ
AdviceMode mode() default AdviceMode.PROXY;
// 为了完成事务管理,会向容器中添加通知
// 这个order属性代表了通知的执行优先级
// 默认是最低优先级
int order() default Ordered.LOWEST_PRECEDENCE;
}
TransactionManagementConfigurationSelector
- 核心内容就是注册
AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
/**
* 子类实现了AdviceModeImportSelector,泛型类型为@EnableTransactionManagement注解
* 重写了selectImports(AdviceMode adviceMode)方法
*/
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* 如果mode是PROXY,那么返回AutoProxyRegistrar和ProxyTransactionManagementConfiguration
* 如果mode是ASPECTJ,那么返回AspectJ(Jta)TransactionManagementConfiguration
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
//一般都是PROXY,因此将会注册AutoProxyRegistrar和ProxyTransactionManagementConfiguration的bean定义,进行动态代理
return new String[]{AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
//支持Aspectj的静态代理织入
return new String[]{determineTransactionAspectClass()};
default:
//其他值则返回null,将会抛出异常
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
- 父类AdviceModeImportSelector实现了ImportSelector接口
- 通用基类,根据注解的AdviceMode来选择注册不同的bean定义
/**
* 这是一个通用基类,用于根据AdviceMode来选择注册不同的bean定义,该基类被用于广泛的支持@Enable*注解
* 比如@EnableAsync、@EnableCaching、@EnableTransactionManagement(需要spring-tx依赖)
*
* @param <A> 注解类型泛型
*/
public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
/**
* AdviceMode属性的默认属性名字为"mode"
*/
public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode";
/**
* 获取AdviceMode属性的属性名,默认为"mode",子类可以覆盖重写
*/
protected String getAdviceModeAttributeName() {
return DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME;
}
/**
* 该方法就是核心方法,在解析@Import注解时就会自动调用
* <p>
* 该方法首先会校验指定的注解中是否存在类型为AdviceMode名字为getAdviceModeAttributeName()返回值的属性
* 然后会调用另一个selectImports(AdviceMode adviceMode)方法,该方法被子类重写,用于根据mode值判断应该使用哪些bean
*/
@Override
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
//获取确定的泛型类型
Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
//获取该泛型注解的属性集合
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (attributes == null) {
throw new IllegalArgumentException(String.format(
"@%s is not present on importing class '%s' as expected",
annType.getSimpleName(), importingClassMetadata.getClassName()));
}
//从属性集合中根据AdviceMode属性的属性名获取属性值
AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
//调用selectImports(AdviceMode adviceMode)方法选择合适bean,该方法被子类重写
String[] imports = selectImports(adviceMode);
//不能为null
if (imports == null) {
throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
}
return imports;
}
/**
* 根据给定的AdviceMode确定应导入哪些类,该方法应被子类重写
* <p>
* 返回null将会抛出IllegalArgumentException异常.
*/
@Nullable
protected abstract String[] selectImports(AdviceMode adviceMode);
}
3、AutoProxyRegistrar注册自动代理创建者
- 这个类实现了
ImportBeanDefinitionRegistrar
,它的作用是向容器中注册别的BeanDefinition
- 直接关注它的registerBeanDefinitions方法即可
// AnnotationMetadata,代表的是AutoProxyRegistrar的导入类的元信息
// 既包含了类元信息,也包含了注解元信息
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
// 获取@EnableTransactionManagement所在配置类上的注解元信息
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
// 遍历注解
for (String annType : annTypes) {
// 可以理解为将注解中的属性转换成一个map
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (candidate == null) {
continue;
}
// 直接从map中获取对应的属性
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
// mode,代理模型,一般都是SpringAOP
// proxyTargetClass,是否使用cglib代理
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
// 注解中存在这两个属性,并且属性类型符合要求,表示找到了合适的注解
candidateFound = true;
// 实际上会往容器中注册一个InfrastructureAdvisorAutoProxyCreator
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
// ......
}
注册核心类的方法栈
@EnableTransactionManagement与@EnableAspectJAutoProxy对比
- 查看注册
AspectJ自动代理类
的方法调用栈 - 调用方法一样,只是事务注册
InfrastructureAdvisorAutoProxyCreator.class
,AspectJ注册AnnotationAwareAspectJAutoProxyCreator.class
- AopConfigUtils类查看不同自动代理注册器下标,
AnnotationAwareAspectJAutoProxyCreator
最大,优先注册
- InfrastructureAdvisorAutoProxyCreator只会使用容器
内部
定义的Advisor - 但是AnnotationAwareAspectJAutoProxyCreator会使用
所有
实现了Advisor接口的通知 - 所有后者可以覆盖(替换)前者
4、ProxyTransactionManagementConfiguration注册事务管理bean
类图:
AbstractTransactionManagementConfiguration抽象父类
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
@Nullable
protected AnnotationAttributes enableTx;
@Nullable
protected TransactionManager txManager;
// 这个方法就是获取@EnableTransactionManagement的属性
// importMetadata:就是@EnableTransactionManagement这个注解所在类的元信息
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
// 将EnableTransactionManagement注解中的属性对存入到map中
// AnnotationAttributes实际上就是个map
this.enableTx = AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
// 这里可以看到,限定了导入的注解必须使用@EnableTransactionManagement
if (this.enableTx == null) {
throw new IllegalArgumentException(
"@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
}
}
// 我们可以配置TransactionManagementConfigurer
// 通过TransactionManagementConfigurer向容器中注册一个事务管理器
// 一般不会这么使用,更多的是通过@Bean的方式直接注册
@Autowired(required = false)
void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
// .....
TransactionManagementConfigurer configurer = configurers.iterator().next();
this.txManager = configurer.annotationDrivenTransactionManager();
}
// 向容器中注册一个TransactionalEventListenerFactory
// 这个类用于处理@TransactionalEventListener注解
// 可以实现对事件的监听,并且在事务的特定阶段对事件进行处理
@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
return new TransactionalEventListenerFactory();
}
}
ProxyTransactionManagementConfiguration核心配置类
// proxyBeanMethods=false,意味着不对配置类生成代理对象
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
// 注册了一个BeanFactoryTransactionAttributeSourceAdvisor
// advisor就是一个绑定了切点的通知
// 可以看到通知就是TransactionInterceptor
// 切点会通过TransactionAttributeSource去解析@Transacational注解
// 只会对有这个注解的方法进行拦截
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
// BeanDefinition的角色是一个基础设施类
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
// 注册一个AnnotationTransactionAttributeSource
// 这个类的主要作用是用来解析@Transacational注解
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
// 事务是通过AOP实现的,AOP的核心就是拦截器
// 这里就是注册了实现事务需要的拦截器
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
// 将AnnotationTransactionAttributeSource注解事务属性源set到事务拦截器对象中
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
总结:
- ProxyTransactionManagementConfiguration类是一个@Configuration配置类
- 通过内部的@Bean方法向容器注入一系列与AOP事务相关的一些基础bean定义
BeanFactoryTransactionAttributeSourceAdvisor事务通知增强器
AnnotationTransactionAttributeSource注解事务属性源
TransactionInterceptor事务拦截器(核心内容)
TransactionalEventListenerFactory事务事件监听器工厂
三、创建代理对象
- 创建代理对象的时机,以及是否提前暴露对象内容与Spring AOP切面一样Spring源码解析(九):AOP源码之@Aspect所有相关注解解析
- 对于事务代理对象,只是在拦截器链中加上事务拦截器TransactionInterceptor
- 由图可知,先执行事务拦截器,再执行切面通知的拦截器,下一章节进入事务拦截器的invoke方法