Spring源码解析(十一):spring事务配置类源码

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的实现类

Spring源码解析(十一):spring事务配置类源码_第1张图片
AbstractPlatformTransactionManager,Spring提供的一个事务管理的基类,提供了事务管理的模板,实现了Spring事务管理的一个标准流程

  1. 判断当前是否已经存在一个事务
  2. 应用合适的事务传播行为
  3. 在必要的时候挂起/恢复事务
  4. 提交时检查事务是否被标记成为rollback-only
  5. 在回滚时做适当的修改(是执行真实的回滚/还是将事务标记成rollback-only
  6. 触发注册的同步回调

AbstractPlatformTransactionManager提供了四个常见的子类,其说明如下

Spring源码解析(十一):spring事务配置类源码_第2张图片

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事务的状态,其继承关系如下:

Spring源码解析(十一):spring事务配置类源码_第3张图片

  • 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

  • 核心内容就是注册AutoProxyRegistrarProxyTransactionManagementConfiguration
/**
 * 子类实现了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  注解类型泛型
 */
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注解时就会自动调用
     * 

* 该方法首先会校验指定的注解中是否存在类型为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确定应导入哪些类,该方法应被子类重写 *

* 返回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;
                }
            }
        }
    }
    // ......
}

注册核心类的方法栈

Spring源码解析(十一):spring事务配置类源码_第4张图片

@EnableTransactionManagement与@EnableAspectJAutoProxy对比

  • 查看注册AspectJ自动代理类的方法调用栈
  • 调用方法一样,只是事务注册InfrastructureAdvisorAutoProxyCreator.class,AspectJ注册AnnotationAwareAspectJAutoProxyCreator.class

Spring源码解析(十一):spring事务配置类源码_第5张图片

  • AopConfigUtils类查看不同自动代理注册器下标,AnnotationAwareAspectJAutoProxyCreator最大,优先注册

Spring源码解析(十一):spring事务配置类源码_第6张图片

  • InfrastructureAdvisorAutoProxyCreator只会使用容器内部定义的Advisor
  • 但是AnnotationAwareAspectJAutoProxyCreator会使用所有实现了Advisor接口的通知
  • 所有后者可以覆盖(替换)前者

4、ProxyTransactionManagementConfiguration注册事务管理bean

类图:

Spring源码解析(十一):spring事务配置类源码_第7张图片

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

Spring源码解析(十一):spring事务配置类源码_第8张图片

  • 由图可知,先执行事务拦截器,再执行切面通知的拦截器,下一章节进入事务拦截器的invoke方法

你可能感兴趣的:(spring,spring,java,数据库)