Spring源码分析:声明式事务梳理

/ Spring源码分析 / 2 条评论 / 460人围观

使用注解方式简单模拟事务

样例

说明

  1. 数据源采用c3p0
  2. 采用JdbcTemplate持久化
  3. 采用Spring事务注解

环境搭建

POM依赖

<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>
<!-- spring提供的jdbcTemplate模块 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.12.RELEASE</version>
</dependency>
<!-- mysql链接驱动包 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.44</version>
    <scope>runtime</scope>
</dependency>
<!-- AOP -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.12.RELEASE</version>
</dependency>

配置类

/**
 * description:声明式事务配置类,其中@EnableTransactionManagement
 * 一定要开启。
 * @author 70KG
 */
@Configuration
@ComponentScan("com.nmys.story.springCore.springaop.tx_sample")
@EnableTransactionManagement // -- 开启基于注解的事务管理
public class TxConfig {

    // -- 配置数据源
    @Bean
    public DataSource dataSource() throws Exception {
        ComboPooledDataSource pool = new ComboPooledDataSource();
        pool.setUser("root");
        pool.setPassword("root");
        pool.setDriverClass("com.mysql.jdbc.Driver");
        pool.setJdbcUrl("jdbc:mysql://localhost:3306/usthe?useSSL=false");
        return pool;
    }

    // -- 加入模板
    @Bean
    public JdbcTemplate jdbcTemplate() throws Exception {
        JdbcTemplate template = new JdbcTemplate(dataSource());
        return template;
    }

    // -- 配置事务管理器,它才是用来提交回滚事务的主导者
    @Bean
    public DataSourceTransactionManager txManager() throws Exception {
        DataSourceTransactionManager tx = new DataSourceTransactionManager(dataSource());
        return tx;
    }

}

业务类

/**
 * description
 * @author 70KG
 */
@Service
public class TxService {

    @Autowired
    private TxDao txDao;

    public void insertLog(){
        txDao.insertSth();
    }

}
/**
 * description
 * @author 70KG
 */
@Repository
public class TxDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    // @Transactional仅表明它是一个事务方法,开启事务仅有注解是不够的,还需要配置事务管理器
    @Transactional
    public void insertSth() {
        String sql = "INSERT into sys_log (username) VALUES(?);";
        jdbcTemplate.update(sql, "lisi");
        System.out.println("------>插入成功");
        int i = 10/0;
    }
}

测试类

/**
 * description
 * @author 70KG
 */
public class Test01 {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(TxConfig.class);
        TxService bean = app.getBean(TxService.class);
        bean.insertLog();
    }

}

测试结果

测试结果肯定是能正常运行的,下面试着跟一下源码。

源码分析

  1. 当容器开始启动运行的时候就会找到@EnableTransactionManagement注解
  2. 进入注解,发现它使用@Import(TransactionManagementConfigurationSelector.class)向容器中注入了这个类
  3. 跟进TransactionManagementConfigurationSelector,发现它最终实现的是ImportSelector接口,这个接口可以向IOC容器中以Bean的全类名的方式注入Bean。 源码如下,AdviceMode在注解@EnableTransactionManagement默认就是PROXY,可见它向容器中注入了两个类,分别是AutoProxyRegistrar和ProxyTransactionManagementConfiguration。
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null;
		}
	}
}

AutoProxyRegistrar

  1. AutoProxyRegistrar翻译过来:自动代理注册器。进入AutoProxyRegistrar类,截取部分源码,如下:
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	boolean candidateFound = false;
	Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
	for (String annoType : annoTypes) {
		AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
		if (candidate == null) {
			continue;
		}
		Object mode = candidate.get("mode");
		Object proxyTargetClass = candidate.get("proxyTargetClass");
		if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
				Boolean.class == proxyTargetClass.getClass()) {
			candidateFound = true;
			if (mode == AdviceMode.PROXY) {
				// -- 前面的代码主要是获取注解类型,注解信息等等。
				// -- 主要是这个地方,如果必要的话,就向容器中注册一个自动代理创建器。
				AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
				if ((Boolean) proxyTargetClass) {
					AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
					return;
				}
			}
		}
	}
    ...........
  1. 进入registerAutoProxyCreatorIfNecessary(registry),AopConfigUtils类中,源码如下:
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,
		@Nullable Object source) {
	// -- 断言
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	// 先判断有没有org.springframework.aop.config.internalAutoProxyCreator
	// 首次进来,肯定没有
	if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
		if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
			int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
			int requiredPriority = findPriorityForClass(cls);
			if (currentPriority < requiredPriority) {
				apcDefinition.setBeanClassName(cls.getName());
			}
		}
		return null;
	}
	// -- 将cls也就是InfrastructureAdvisorAutoProxyCreator包装成RootBeanDefinition
	RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
	beanDefinition.setSource(source);
	beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
	beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	// -- 将beanDefinition注册到IOC容器中,Bean的
	// -- 名字就叫org.springframework.aop.config.internalAutoProxyCreator
	registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
	return beanDefinition;
}
  1. 向容器中注入了InfrastructureAdvisorAutoProxyCreator,进入此类,发现父类是AbstractAdvisorAutoProxyCreator,AbstractAdvisorAutoProxyCreator的父类是AbstractAutoProxyCreator,AbstractAutoProxyCreator中的方法,创建并返回了代理类,如下:
/**
 * Create a proxy with the configured interceptors if the bean is
 * identified as one to proxy by the subclass.
 * @see #getAdvicesAndAdvisorsForBean
 */
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (!this.earlyProxyReferences.contains(cacheKey)) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

给容器中注入InfrastructureAdvisorAutoProxyCreator的主要作用就是,利用后置处理器机制在对象创建以后,对对象进行包装,返回一个代理对象(增强器),代理对象执行方法,利用拦截器链进行调用。

ProxyTransactionManagementConfiguration

  1. 进入ProxyTransactionManagementConfiguration,部分源码如下:
// -- 向容器中注入名字为TRANSACTION_ADVISOR_BEAN_NAME的切面
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
	BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        // -- 向切面中注入注解解析器,专门来解析事务注解的
	advisor.setTransactionAttributeSource(transactionAttributeSource());
        // -- 向切面中注入事务的拦截器,专门来拦截方法,包括事务的提交以及回滚操作
	advisor.setAdvice(transactionInterceptor());
	if (this.enableTx != null) {
		advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
	}
	return advisor;
}
  1. 进入transactionAttributeSource()注解解析器,源码如下:
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
	this.publicMethodsOnly = publicMethodsOnly;
	this.annotationParsers = new LinkedHashSet<>(2);
        // -- Spring注解的解析器
	this.annotationParsers.add(new SpringTransactionAnnotationParser());
	if (jta12Present) {
                // -- jta的解析器
		this.annotationParsers.add(new JtaTransactionAnnotationParser());
	}
	if (ejb3Present) {
                // -- ejb的解析器
		this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
	}
}
  1. 进入SpringTransactionAnnotationParser(),部分源码如下:
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
	RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
	Propagation propagation = attributes.getEnum("propagation");
	rbta.setPropagationBehavior(propagation.value());
	Isolation isolation = attributes.getEnum("isolation");
	rbta.setIsolationLevel(isolation.value());
	rbta.setTimeout(attributes.getNumber("timeout").intValue());
	rbta.setReadOnly(attributes.getBoolean("readOnly"));
	rbta.setQualifier(attributes.getString("value"));
	ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<>();
	Class<?>[] rbf = attributes.getClassArray("rollbackFor");
	for (Class<?> rbRule : rbf) {

会发现@Transactional中的各种属性都在这里,这样,注解解析器就分析完了

  1. 再来看事务的拦截器,分析事务是如何回滚和提交的,进入transactionInterceptor()
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
        // -- 事务的拦截器
	TransactionInterceptor interceptor = new TransactionInterceptor();
	interceptor.setTransactionAttributeSource(transactionAttributeSource());
	if (this.txManager != null) {
                // -- 将事务管理器设置进去,为了事务的提交和回滚操作
		interceptor.setTransactionManager(this.txManager);
	}
	return interceptor;
}

TransactionInterceptor 是一个实现了MethodInterceptor接口的类,标志着TransactionInterceptor是一个方法拦截器,进入它的invoke()方法

@Override
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
	// Work out the target class: may be {@code null}.
	// The TransactionAttributeSource should be passed the target class
	// as well as the method, which may be from an interface.
	Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
	// Adapt to TransactionAspectSupport's invokeWithinTransaction...
	return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

进入invokeWithinTransaction()

@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
		final InvocationCallback invocation) throws Throwable {
	// If the transaction attribute is null, the method is non-transactional.
	TransactionAttributeSource tas = getTransactionAttributeSource();
        // -- 拿到事务注解信息包括事务的qualifier和rollback信息
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        // -- 获取事务管理器
	final PlatformTransactionManager tm = determineTransactionManager(txAttr);
        // -- 事务连接点的定义信息
	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
	if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
		// 创建并开启事务
		TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
		Object retVal = null;
		try {
			// This is an around advice: Invoke the next interceptor in the chain.
			// This will normally result in a target object being invoked.
                        // -- 调用目标方法
			retVal = invocation.proceedWithInvocation();
		}
		catch (Throwable ex) {
			// target invocation exception
                        // -- 出现异常了,获取事务管理器,进行事务的回滚
			completeTransactionAfterThrowing(txInfo, ex);
			throw ex;
		}
		finally {
			cleanupTransactionInfo(txInfo);
		}
                // -- 未出现异常,也获取事务管理器则进行事务的提交
		commitTransactionAfterReturning(txInfo);
		return retVal;
	}
    .........

总结

Spring事务源码梳理

  1. 通过注解@EnableTransactionManagement中的@Import(TransactionManagementConfigurationSelector.class)给容器中导入了两个组件,分别是:AutoProxyRegistrar和ProxyTransactionManagementConfiguration
  2. AutoProxyRegistrar:它是一个后置处理器,给容器中注册一个InfrastructureAdvisorAutoProxyCreator,InfrastructureAdvisorAutoProxyCreator利用后置处理器机制在对象创建以后,对对象进行包装,返回一个代理对象(增强器),代理对象执行方法,利用拦截器链进行调用。
  3. ProxyTransactionManagementConfiguration:给容器中注册事务增强器
  1. lkjklm

    回复
  2. mjhjhjk

    回复