可能是最卷的Spring源码系列(十五):事务

spring中事务流程跟aop基本上是一样的,所以还是安装上篇的套路,先看看事务是如何使用的,再分析源码

事务的使用

本文为了清晰的演示事务,所以不使用mybatis,很多时候我们用了这些成熟的框架之后,根本无法理解其原理,有的时候还是多要用用底层的方式进行学习。

@Component
@EnableTransactionManagement
public class TransactionConfig {
	@Bean
	public DataSource dataSource() {
		DruidDataSource dataSource = new DruidDataSource();
		dataSource.setUsername("root");
		dataSource.setPassword("123456");
		dataSource.setUrl("jdbc:mysql://39.105.156.80:3306/demo");
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		return dataSource;
	}
	@Bean
	public JdbcTemplate jdbcTemplate(DataSource dataSource) {
		return new JdbcTemplate(dataSource);
	}

	@Bean
	public PlatformTransactionManager transactionManager(DataSource dataSource) {
		return new DataSourceTransactionManager(dataSource);
	}

}

数据库操作

@Slf4j
public class TestDao {
	@Autowired
	JdbcTemplate jdbcTemplate;
	@Transactional(rollbackFor = Exception.class)
	public String select(){
		jdbcTemplate.execute("INSERT INTO `demo`.`blog` (`title`, `content`) VALUES ('222', '222');");
		log.info("select");
		int a  = 5/0;
		return "";
	}
}

测试类

public class TestTransaction {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
		ac.register(TransactionConfig.class);
		ac.register(TestDao.class);
		ac.refresh();
		TestDao bean = ac.getBean(TestDao.class);
		bean.select();

	}
}

所以使用事务有如下几个步骤
1、@EnableTransactionManagement注解
2、往spring中注入一个DataSourceTransactionManager
3、在方法上加上@Transactional(rollbackFor = Exception.class)
之后当执行该方法,该方法抛出异常时,会执行回滚操作,那么spring是如何实现的事务呢?我们接下来一步步分析

源码分析

@EnableTransactionManagement注解分析

就是一个组合注解
在这里插入图片描述
默认会走proxy
在这里插入图片描述

结果就是注入了两个类
AutoProxyRegistrar.class
ProxyTransactionManagementConfiguration.class

AutoProxyRegistrar
@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		// 拿出所有的注解
		Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
		for (String annType : annTypes) {
			// 查找有mode和proxyTargetClass的注解
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
			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) {
					// 注入了InfrastructureAdvisorAutoProxyCreator.class
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					if ((Boolean) proxyTargetClass) {
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}
		if (!candidateFound && logger.isInfoEnabled()) {
			String name = getClass().getSimpleName();
			logger.info(String.format("%s was imported but no annotations were found " +
					"having both 'mode' and 'proxyTargetClass' attributes of type " +
					"AdviceMode and boolean respectively. This means that auto proxy " +
					"creator registration and configuration may not have occurred as " +
					"intended, and components may not be proxied as expected. Check to " +
					"ensure that %s has been @Import'ed on the same class where these " +
					"annotations are declared; otherwise remove the import of %s " +
					"altogether.", name, name, name));
		}
	}

这里完成了InfrastructureAdvisorAutoProxyCreator的注入,InfrastructureAdvisorAutoProxyCreator的继承关系如下
在这里插入图片描述
对比下aop的
在这里插入图片描述

这一步最重要的就是向Spring容器注入了一个自动代理创建器: org.springframework.aop.config.internalAutoProxyCreator,这里有个小细节注意一下,由于AOP和事务注册的都是 名字为org.springframework.aop.config.internalAutoProxyCreator 的BeanPostProcessor,但是只会保留一个,AOP的会 覆盖事务的, 因为AOP优先级更大
所以假如@EnableTransactionManagement和@EnableAspectJAutoProxy 同时存在, 那么AOP的 AutoProxyCreator 会进行覆盖。

ProxyTransactionManagementConfiguration

这是一个配置类

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	//注入了一个advisor
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@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;
	}

	// TransactionAttributeSource 这种类特别像 `TargetSource`这种类的设计模式
	// 这里直接使用的是AnnotationTransactionAttributeSource 基于注解的事务属性源
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}


	// 事务拦截器,它是个`MethodInterceptor`,它也是Spring处理事务最为核心的部分
	// 请注意:你可以自己定义一个TransactionInterceptor(同名的),来覆盖此Bean(注意是覆盖)
	// 另外请注意:你自定义的BeanName必须同名,也就是必须名为:transactionInterceptor 否则两个都会注册进容器里面去
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		// 事务的属性
		interceptor.setTransactionAttributeSource(transactionAttributeSource);
		// 事务管理器(也就是注解最终需要使用的事务管理器,父类已经处理好了)
		// 此处注意:我们是可议不用特殊指定的,最终它自己会去容器匹配一个适合的
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

分析下它的父类

@Configuration
//实现了ImportAware接口,可以拿到@Import所在类的所有注解信息
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {

	@Nullable
	protected AnnotationAttributes enableTx;

	/**
	 * Default transaction manager, as configured through a {@link TransactionManagementConfigurer}.
	 */
	// 注解的默认的事务处理器(可通过实现接口TransactionManagementConfigurer来自定义配置)
	@Nullable
	protected TransactionManager txManager;


	@Override
	public void setImportMetadata(AnnotationMetadata importMetadata) {
		// 此处:只拿到@EnableTransactionManagement这个注解的就成~~~~~ 作为AnnotationAttributes保存起来
		this.enableTx = AnnotationAttributes.fromMap(
				importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
		if (this.enableTx == null) {
			throw new IllegalArgumentException(
					"@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
		}
	}

	// 可以配置一个Bean实现这个接口。然后给注解驱动的给一个默认的事务管理器~~~~
	@Autowired(required = false)
	void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
		if (CollectionUtils.isEmpty(configurers)) {
			return;
		}
		if (configurers.size() > 1) {
			throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
		}
		TransactionManagementConfigurer configurer = configurers.iterator().next();
		this.txManager = configurer.annotationDrivenTransactionManager();
	}

	// 注册一个监听器工厂,用以支持@TransactionalEventListener注解标注的方法,来监听事务相关的事件
	// 通过事件监听模式来实现事务的监控~~~~
	@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
		return new TransactionalEventListenerFactory();
	}

}

这里相当于注册了一个Advisor,事务的流程跟aop类似

BeanFactoryTransactionAttributeSourceAdvisor

这个类里面有一个重要的属性 在这里插入图片描述

TransactionAttributeSourcePointcut

提供了matches方法,代理过程中会调用这个方法进行匹配,来判断是否需要事务
在这里插入图片描述
getTransactionAttribute方法最终在AbstractFallbackTransactionAttributeSource中实现

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		if (method.getDeclaringClass() == Object.class) {
			return null;
		}

		// First, see if we have a cached value.
		Object cacheKey = getCacheKey(method, targetClass);
		TransactionAttribute cached = this.attributeCache.get(cacheKey);
		if (cached != null) {
			// Value will either be canonical value indicating there is no transaction attribute,
			// or an actual transaction attribute.
			if (cached == NULL_TRANSACTION_ATTRIBUTE) {
				return null;
			}
			else {
				return cached;
			}
		}
		else {
			// We need to work it out.
			TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
			// Put it in the cache.
			if (txAttr == null) {
				this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
			}
			else {
				String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
				if (txAttr instanceof DefaultTransactionAttribute) {
					((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
				}
				this.attributeCache.put(cacheKey, txAttr);
			}
			return txAttr;
		}
	}
	```
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值