Spring 事务利用AOP原理实现,主要过程和AOP原理一样,可以分为三步,启用事务、生成代理对对象、执行。
从如何使用事务开始
本实例使用Spring的 JdbcTemplate 作为操作数据库的工具,使用 druid 做为数据库连接池。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
|
- 在配置类上加上 @EnableTransactionManagement 注解表示开启Spring事务功能
1
2
3
|
@ComponentScan("com.example")
@EnableTransactionManagement
public class ApplicationMain {}
|
- 配置数据源、配置JdbcTemplate、配置事务管理器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@Configuration
public class JdbcConfig {
@Bean(initMethod = "init")
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=utf-8");
dataSource.setUsername("root");
dataSource.setPassword("rootroot");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public TransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
|
1
2
3
4
5
6
|
create table blog
(
id int auto_increment comment 'id' primary key,
title varchar(20) null comment '标题',
content varchar(100) null comment '内容'
) comment 'blog表';
|
1
2
3
4
5
6
7
8
9
10
|
@Getter
@Setter
@ToString
@Accessors(chain = true)
public class Blog {
private Integer id;
private String title;
private String content;
}
|
- 创建 BlogService和一个 insert 方法插入一条记录,在方法上加上 @Transactional 注解,在执行插入数据成功后故意写个异常情况1/0,测试事务是否回滚。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Service
@AllArgsConstructor
public class BlogService {
private final JdbcTemplate jdbcTemplate;
@Transactional(rollbackFor = Exception.class)
public int insert(Blog blog) {
String sql = "insert into blog(title,content) value(?,?)";
Object[] args = new Object[]{blog.getTitle(), blog.getContent()};
int ret = jdbcTemplate.update(sql, args);
System.out.println(1 / 0);
return ret;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
|
@ComponentScan("com.example")
@EnableTransactionManagement
public class ApplicationMain {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationMain.class);
BlogService blogService = context.getBean(BlogService.class);
Blog blog = new Blog().setTitle("xxx222").setContent("xxx2222");
System.out.println(blogService.insert(blog));
}
}
|
从执行结果看,后面的代码抛异常后,事务回滚了,那个仅凭一个简单的注解事务是如何开启、提交已经回滚的呢,下面我们从底层源码一探究竟。
从事务的入口 开始
@EnableTransactionManagement
点开 @EnableTransactionManagement 注解,我们发现他导入了另一类@Import(TransactionManagementConfigurationSelector.class),@Import
的作用是它可以导入一个普通类到Spring容器中,使其注册为一个bean。
TransactionManagementConfigurationSelector 类它有实现了 ImportSelector 接口,重写了 selectImports
方法,该方法会在Spring扫描的时候执行,通过返回的类名数组生成bean,最后发现添加EnableTransactionManagement注解的最终目的是注入 AutoProxyRegistrar 和
ProxyTransactionManagementConfiguration 这两个类到Spring容器。
AutoProxyRegistrar
1
|
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
|
1
2
3
4
5
6
|
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
@Nullable
private ConfigurableListableBeanFactory beanFactory;
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
this.beanFactory = beanFactory;
}
@Override
protected boolean isEligibleAdvisorBean(String beanName) {
return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}
}
|
AutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar,重写了 registerBeanDefinitions
方法,该方法在Spring容器启动的时候回执行,可以注册bean定义,在这里核心是注册了另一个 bean
InfrastructureAdvisorAutoProxyCreator,InfrastructureAdvisorAutoProxyCreator方法中几乎没有什么核心代码,它的全部功能来源于 AOP 解析类
AbstractAdvisorAutoProxyCreator。
ProxyTransactionManagementConfiguration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@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;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@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;
}
}
|
ProxyTransactionManagementConfiguration 类是一个配置类,他注册了三个bean。
- BeanFactoryTransactionAttributeSourceAdvisor 它是一个Advisor,实现了Advisor 接口,它是是AOP的其中一种方式和 @Aspect 注解效果是一样的,都会被AOP解析识别。
- AnnotationTransactionAttributeSource 是事务属性源,他主要负责判断一个bean及其方法是不是有@Transactional注解,如果有就要生成动态代理。
- TransactionInterceptor 该类是代理类具体实现逻辑,生成代理代理对象时会用到,在具体执行事务时会调用其中的 invock 方法。
另外 AnnotationTransactionAttributeSource 和 TransactionInterceptor 都是 BeanFactoryTransactionAttributeSourceAdvisor
的属性,具体的调用在BeanFactoryTransactionAttributeSourceAdvisor 完成。
以上就是启用事务时所作的事情。
何时生成代理对象
什么时候生成代理对象 ?
为那些bean生成代理对象?
InfrastructureAdvisorAutoProxyCreator
还记得它吗,该对象时具体扫描 @Transactional 标注的类和方法,再生成代理对象的,但是它的核心功能都是继承自AOP的对象AbstractAdvisorAutoProxyCreator
的,所以说事务的实现在于创建了符合AOP规则的 Advisor(BeanFactoryTransactionAttributeSourceAdvisor) ,然后交给AOP去生成代理对象,
AOP 在哪里找到 BeanFactoryTransactionAttributeSourceAdvisor ?
何时调用事务方法
未完