背景
Spring使用声明式让我们无需关系事务的复杂逻辑处理,只要添加注解@Transactional即可为业务添加事务支持
如何启用Spring事务
注解方式@EnableTransactionManagement
- 还需要加@Configuration
- 使用注解方法启动必须使用基于注解的容器启动,这里就不列出例子了
//基于注解的容器 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); //扫包 ctx.scan("com.example");
XML配置文件启用
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"
default-autowire="byName">
<!--启用声明式事务-->
<tx:annotation-driven/>
<!--当然是配置datasource了-->
<jdbc:embedded-database id="dataSource" type="H2">
<!--一定要是先DDL,即数据库定义语言-->
<jdbc:script location="classpath:sql/h2-schema.sql"/>
<!--然后才是DML,数据库操作语言-->
<jdbc:script location="classpath:sql/h2-data.sql" encoding="UTF-8"/>
</jdbc:embedded-database>
<!--事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--查询服务-->
<bean id="userService" class="com.example.springtest.transaction.UserServiceImpl"/>
</beans>
数据库脚本
-- h2-schame.sql
drop table if exists t_user ;
-- 创建表
create table t_user(
id int primary key auto_increment,
name varchar(20),
age int
);
-- 插入表数据 h2-data.sql
insert into t_user(name,age) values('小明',23);
insert into t_user(name,age) values('小白',24);
在查询方法上声明注解@Transactional
默认发生RuntimeException异常时,事务会回滚
@Transactional
public void insertUser() throws SQLException {
//使用Spring提供的工具类,获取当前线程的连接-已经在事务拦截器中创建了连接
Connection connection = DataSourceUtils.getConnection(dataSource);
//获取JDBC 执行SQL的对象
Statement statement = connection.createStatement();
//执行插入语句
statement.execute("insert into t_user(name,age) values('小黑',100)");
}
Spring如何支持声明式事务
使用XML方式启动
首先需要支持解析自定义标签annotation-driven
- 全局搜索annotation-driven
- 在TxNamespaceHandler中支持自定义标签annotation-driven
public class TxNamespaceHandler extends NamespaceHandlerSupport {
static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
static String getTransactionManagerName(Element element) {
return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
}
@Override
public void init() {
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
//支持声明式事务标签
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
}
AnnotationDrivenBeanDefinitionParser
- 解析标签并注册Spring事务相关的Bean
- 下面主要注册四大Bean
- InfrastructureAdvisorAutoProxyCreator
- 继承了SmartInstantiationAwareBeanPostProcessor 用于执行Bean的后置处理器,返回代理Bean的Proxy对象
- TransactionInterceptor
- 继承了MethodIntercetor和Advice 用于代理增强
- 用于执行事务相关的逻辑
- BeanFactoryTransactionAttributeSourceAdvisor
- 用于判断Bean中的方法是否需要代理增强
- AnnotationTransactionAttributeSource
- 保存注解中的一些属性信息
- InfrastructureAdvisorAutoProxyCreator
- parse() 被容器调用的标签解析方法,从中执行事务相关的BeanDefinition的创建逻辑
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
//使用aspectj支持事务
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
registerJtaTransactionAspect(element, parserContext);
}
}
//默认
else {
// mode="proxy"
//配置代理相关的逻辑
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}
- configureAutoProxyCreator() 默认配置方法
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
//主要用于注册InfrastructureAdvisorAutoProxyCreator的BeanDefinition
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);
// Create the TransactionAttributeSource definition.
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
//创建TransactionInterceptor definition,用于拦截事务
//就是这个类对事务的逻辑处理
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registerTransactionManager(element, interceptorDef);
//构造Bean定义的 transactionAttributeSource='sourceName的Bean名称'
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
// 创建 TransactionAttributeSourceAdvisor definition.
// 用于判断Bean中的Method是否需要使用事务的Advice进行争强
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//构造Bean定义的属性
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
//注册BeanFactoryTransactionAttributeSourceAdvisor的BeanDefinition
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
parserContext.registerComponent(compositeDef);
}
}
使用注解方式启动@EnableTransactionManagement
- @EnableTransactionManagement 等同于xml中的annotation-driven
- TransactionManagementConfigurationSelector中就是声明事务相关的Bean,与XML方式创建的Bean是一样的
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//导入事务相关的Bean的配置类
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
/*
* 是否强制使用GCLIB生成代理对象
* */
boolean proxyTargetClass() default false;
/*
* 使用proxy或aspectj支持事务
* */
AdviceMode mode() default AdviceMode.PROXY;
/*
* 事务拦截器在增强器中的执行顺序
* */
int order() default Ordered.LOWEST_PRECEDENCE;
}
Spring何时对Bean进行事务增强
首先对Bean添加事务注解
- 我在UserService中对insertUser()添加了@Transactional注解
public class UserService {
DataSource dataSource;
PlatformTransactionManager transactionManager;
@Transactional
public void insertUser() throws SQLException {
//使用Spring提供的工具类,获取当前线程的连接-已经在事务拦截器中创建了连接
Connection connection = DataSourceUtils.getConnection(dataSource);
//获取JDBC 执行SQL的对象
Statement statement = connection.createStatement();
//执行插入语句
statement.execute("insert into t_user(name,age) values('小黑',100)");
}
- 并在XML配置文件中进行了Bean的声明
<bean id="userService" class="com.example.springtest.transaction.UserServiceImpl"/>
从容器中获取UserService
- 从图中能看到返回的是UserService的代理类
很明显能看到使用了JdkDynamicAopProxy
- 该类用于Spring AOP中使用JDK动态代理创建代理对象
- 在上一篇文章中Spring AOP初始化及执行过程
,最后就是使用JdkDynamicAopProxy对Bean进行代理增强 - 所以说,Spring使用了AOP对事务进行了增强
既然Spring使用AOP对事务进行增强,那么我们知道Spring AOP在AbstractAutoProxyCreator类中的postProcessAfterInitialization()返回代理对象
-
首先来到AbstractAutoProxyCreator并在postProcessAfterInitialization()中打条件断点
-
启动容器
-
如图,当前执行对Bean UserService对象进行代理判断
-
断点进入wrapIfNecessary()
-
从这里我们看到Bean是在Bean的后置处理器InfrastructureAdvisorAutoProxyCreator的父类AbstractAutoProxyCreator中的postProcessAfterInitialization()使用事务增强并被代理返回的
Spring AOP使用了哪个增强器对事务进行增强
- 继续打断点
- 从新启动容器
- 图中看到
- 增强器为BeanFactoryTransactionAttributeSourceAdvisor,
- 对应的增强类(通知Advice)为TransactionInterceptor
总结
- Spring可以使用XML或注解方式启动事务
- Spring通过AOP对事务进行实现
- 在Bean后置处理器InfrastructureAdvisorAutoProxyCreator中对Bean进行代理返回代理Bean
- 事务增强器BeanFactoryTransactionAttributeSourceAdvisor
- 用于匹配当前Bean是否需要事务增强
- 其他略
- 使用TransactionInterceptor对Bean进行事务增强逻辑