使用注解方式简单模拟事务
样例
说明
- 数据源采用c3p0
- 采用JdbcTemplate持久化
- 采用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();
}
}
<!--more-->
/**
* 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();
}
}
测试结果
测试结果肯定是能正常运行的,下面试着跟一下源码。
源码分析
- 当容器开始启动运行的时候就会找到@EnableTransactionManagement注解
- 进入注解,发现它使用@Import(TransactionManagementConfigurationSelector.class)向容器中注入了这个类
- 跟进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
- 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;
}
}
}
}
...........
- 进入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;
}
- 向容器中注入了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
- 进入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;
}
- 进入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());
}
}
- 进入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中的各种属性都在这里,这样,注解解析器就分析完了
- 再来看事务的拦截器,分析事务是如何回滚和提交的,进入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事务源码梳理
- 通过注解@EnableTransactionManagement中的@Import(TransactionManagementConfigurationSelector.class)给容器中导入了两个组件,分别是:AutoProxyRegistrar和ProxyTransactionManagementConfiguration
- AutoProxyRegistrar:它是一个后置处理器,给容器中注册一个InfrastructureAdvisorAutoProxyCreator,InfrastructureAdvisorAutoProxyCreator利用后置处理器机制在对象创建以后,对对象进行包装,返回一个代理对象(增强器),代理对象执行方法,利用拦截器链进行调用。
- ProxyTransactionManagementConfiguration:给容器中注册事务增强器
- 事务增强器要用事务注解信息:AnnotationTransactionAttributeSource来解析事务注解
- 事务拦截器中:transactionInterceptor(),它是一个TransactionInterceptor(保存了事务属性信息和事务管理器),而TransactionInterceptor是一个MethodInterceptor,在目标方法执行的时候,执行拦截器链,事务拦截器(首先获取事务相关的属性,再获取PlatformTransactionManager,如果没有指定任何transactionManager,最终会从容器中按照类型获取一个PlatformTransactionManager,最后执行目标方法,如果异常,便获取到事务管理器进行回滚,如果正常,同样拿到事务管理器提交事务。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。