Spring之事务源码理解,Spring4.3.12.RELEASE版本

1、声明式事务,境搭建环。在pom.xml配置文件中新增依赖的jar包,导入相关依赖,数据源、数据驱动、Spring-jdbc模块。如下所示:

 1 <project xmlns="http://maven.apache.org/POM/4.0.0"
 2     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
 4     http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6     <groupId>com.bie</groupId>
 7     <artifactId>spring-tx-sourceCode</artifactId>
 8     <version>0.0.1-SNAPSHOT</version>
 9 
10 
11     <dependencies>
12         <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
13         <dependency>
14             <groupId>org.springframework</groupId>
15             <artifactId>spring-context</artifactId>
16             <version>4.3.12.RELEASE</version>
17         </dependency>
18         <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
19         <dependency>
20             <groupId>org.projectlombok</groupId>
21             <artifactId>lombok</artifactId>
22             <version>1.18.8</version>
23             <scope>provided</scope>
24         </dependency>
25         <!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
26         <dependency>
27             <groupId>javax.inject</groupId>
28             <artifactId>javax.inject</artifactId>
29             <version>1</version>
30         </dependency>
31         <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
32         <dependency>
33             <groupId>com.mchange</groupId>
34             <artifactId>c3p0</artifactId>
35             <version>0.9.5.2</version>
36         </dependency>
37         <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
38         <dependency>
39             <groupId>mysql</groupId>
40             <artifactId>mysql-connector-java</artifactId>
41             <version>5.1.44</version>
42         </dependency>
43         <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
44         <dependency>
45             <groupId>org.springframework</groupId>
46             <artifactId>spring-aop</artifactId>
47             <version>4.3.12.RELEASE</version>
48         </dependency>
49         <dependency>
50             <groupId>org.springframework</groupId>
51             <artifactId>spring-aspects</artifactId>
52             <version>4.3.12.RELEASE</version>
53         </dependency>
54         <dependency>
55             <groupId>org.springframework</groupId>
56             <artifactId>spring-jdbc</artifactId>
57             <version>4.3.12.RELEASE</version>
58         </dependency>
59 
60     </dependencies>
61 </project>

配置数据源,JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据。使用@EnableTransactionManagement注解,开启基于注解的事务管理功能。配置事务管理器来控制事务,注册事务管理器PlatformTransactionManager到容器中。

 1 package com.bie.tx;
 2 
 3 import java.beans.PropertyVetoException;
 4 
 5 import javax.sql.DataSource;
 6 
 7 import org.springframework.context.annotation.Bean;
 8 import org.springframework.context.annotation.ComponentScan;
 9 import org.springframework.context.annotation.Configuration;
10 import org.springframework.jdbc.core.JdbcTemplate;
11 import org.springframework.jdbc.datasource.DataSourceTransactionManager;
12 import org.springframework.transaction.PlatformTransactionManager;
13 import org.springframework.transaction.annotation.EnableTransactionManagement;
14 
15 import com.mchange.v2.c3p0.ComboPooledDataSource;
16 
17 /**
18  * 
19  *
20  * @Title: TransactionConfig.java
21  * @Package com.bie.tx
22  * @Description: TODO
23  * @author biehl
24  * @date 2019年12月19日
25  * @version V1.0
26  * 
27  *          声明式事务,境搭建环
28  * 
29  *          1、导入相关依赖,数据源、数据驱动、Spring-jdbc模块。
30  *          2、配置数据源,JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据。
31  *          3、@EnableTransactionManagement注解,开启基于注解的事务管理功能。
32  * 
33  *          4、配置事务管理器来控制事务。
34  * 
35  */
36 @EnableTransactionManagement // 第一步、开启基于注解的事务管理功能。
37 @Configuration
38 @ComponentScan(basePackages = { "com.bie" })
39 public class TransactionConfig {
40 
41     /**
42      * 配置连接mysql的配置信息
43      * 
44      * @return
45      * @throws PropertyVetoException
46      */
47     @Bean
48     public DataSource dataSource() throws PropertyVetoException {
49         ComboPooledDataSource dataSource = new ComboPooledDataSource();
50         dataSource.setUser("root");
51         dataSource.setPassword("123456");
52         dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/biehl");
53         dataSource.setDriverClass("com.mysql.jdbc.Driver");
54         return dataSource;
55     }
56 
57     /**
58      * 从数据源中获取到连接
59      * 
60      * @param dataSource
61      *            从IOC容器中获取到DataSource对象
62      * @return
63      */
64     @Bean
65     public JdbcTemplate jdbcTemplate(DataSource dataSource) {
66         // Spring对@Configuration会进行特殊处理。给容器加入组件的方法,多次调用都只是从容器中找组件而已。
67         JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
68         // JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
69         return jdbcTemplate;
70     }
71 
72     /**
73      * 第三步、注册事务管理器到容器中
74      * 
75      * @param dataSource
76      *            事务管理器要管理好数据源
77      * @return
78      */
79     @Bean
80     public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
81         return new DataSourceTransactionManager(dataSource);
82     }
83 
84 }

事务配置三步走。
第一步、开启基于注解的事务管理功能。
第二步、事务方法,如果程序出现异常进行回滚操作。
第三步、注册事务管理器到容器中。

创建User实体类,如下所示:

 1 package com.bie.po;
 2 
 3 import lombok.AllArgsConstructor;
 4 import lombok.Data;
 5 import lombok.NoArgsConstructor;
 6 
 7 /**
 8  * 
 9  *
10  * @Title: User.java
11  * @Package com.bie.po
12  * @Description: TODO
13  * @author biehl
14  * @date 2019年12月19日
15  * @version V1.0
16  *
17  */
18 @Data
19 @AllArgsConstructor
20 @NoArgsConstructor
21 public class User {
22 
23     private int id;
24     private String name;
25     private int age;
26 }

创建dao层的数据交互层,用于和数据库进行交互的代码。

 1 package com.bie.dao;
 2 
 3 /**
 4  * 
 5  *
 6  * @Title: UserDao.java
 7  * @Package com.bie.dao
 8  * @Description: TODO
 9  * @author biehl
10  * @date 2019年12月19日
11  * @version V1.0
12  *
13  */
14 public interface UserDao {
15 
16     /**
17      * 
18      */
19     public void insert();
20 
21 }
 1 package com.bie.dao.impl;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.jdbc.core.JdbcTemplate;
 5 import org.springframework.stereotype.Repository;
 6 
 7 import com.bie.dao.UserDao;
 8 
 9 /**
10  * 
11  *
12  * @Title: UserDaoImpl.java
13  * @Package com.bie.dao
14  * @Description: TODO
15  * @author biehl
16  * @date 2019年12月19日
17  * @version V1.0
18  *
19  */
20 @Repository
21 public class UserDaoImpl implements UserDao {
22 
23     @Autowired
24     private JdbcTemplate jdbcTemplate;
25 
26     public void insert() {
27         String sql = "INSERT INTO biehl.user( name, age) VALUES (?, ?)";
28         String username = "张三三";
29         int age = 25;
30         jdbcTemplate.update(sql, username, age);
31     }
32 
33 }

创建service层的业务逻辑层,用于调用dao层。

 1 package com.bie.service;
 2 
 3 /**
 4  * 
 5  *
 6  * @Title: UserService.java
 7  * @Package com.bie.service
 8  * @Description: TODO
 9  * @author biehl
10  * @date 2019年12月19日
11  * @version V1.0
12  *
13  */
14 public interface UserService {
15 
16     /**
17      * 
18      */
19     public void insert();
20 }
 1 package com.bie.service.impl;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.stereotype.Service;
 5 import org.springframework.transaction.annotation.Transactional;
 6 
 7 import com.bie.dao.UserDao;
 8 import com.bie.service.UserService;
 9 
10 /**
11  * 
12  *
13  * @Title: UserServiceImpl.java
14  * @Package com.bie.service.impl
15  * @Description: TODO
16  * @author biehl
17  * @date 2019年12月19日
18  * @version V1.0
19  *
20  *          Service层添加事务,如果在程序出现异常,之前执行的sql出现回滚。
21  * 
22  *          给方法标注@Transactional,表示当前方法是一个事务方法。
23  */
24 @Service
25 public class UserServiceImpl implements UserService {
26 
27     @Autowired
28     private UserDao userDao;
29 
30     /**
31      * 
32      */
33     @Override
34     @Transactional // 第二步、事务方法,如果程序出现异常进行回滚操作。
35     public void insert() {
36         userDao.insert();
37         System.out.println("插入成功了咯.......");
38         int i = 1 / 0;
39     }
40 
41 }

主启动类,如下所示:

 1 package com.bie.main;
 2 
 3 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 4 
 5 import com.bie.service.UserService;
 6 import com.bie.tx.TransactionConfig;
 7 
 8 /**
 9  * 
10  *
11  * @Title: SpringTransactionApplication.java
12  * @Package com.bie.main
13  * @Description: TODO
14  * @author biehl
15  * @date 2019年12月19日
16  * @version V1.0
17  *
18  */
19 public class SpringTransactionApplication {
20 
21     public static void main(String[] args) {
22         AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TransactionConfig.class);
23         UserService userService = ac.getBean(UserService.class);
24         userService.insert();
25 
26         ac.close();
27     }
28 
29 }

2、Spring事务源码分析,如下所示:

默认之前分析AOP源码,首先从这个注解@EnableTransactionManagement,开启基于注解的事务管理功能,开始进行研究。

该注解@EnableTransactionManagement利用TransactionManagementConfigurationSelector给容器中会导入组件。

即该注解@Import(TransactionManagementConfigurationSelector.class)给容器中会导入组件,TransactionManagementConfigurationSelector是一个Selector。

@EnableTransactionManagement利用TransactionManagementConfigurationSelector给容器中会导入组件。

点进去TransactionManagementConfigurationSelector可以看到,TransactionManagementConfigurationSelector继承了AdviceModeImportSelector<EnableTransactionManagement>。

点进去AdviceModeImportSelector可以看到,抽象类AdviceModeImportSelector<A extends Annotation>实现了接口ImportSelector。

ImportSelector是Import的选择器。ImportSelector是一个接口,规定方法selectImports,返回值String[]字符串数组,数组里面就是类的全类名,返回需要导入的组件的全类名数组。

由于接口ImportSelector只有一个方法String[] selectImports(AnnotationMetadata importingClassMetadata);而类TransactionManagementConfigurationSelector进行了实现,所以将断点打到该方法上。

由于方法栈,里面步骤很多,之前分析AOP源码的时候,大概过了一下,这里自己也可以进行分析即可。分析以后走到断点处。

经过上述分析,可以看到该注解@EnableTransactionManagement给Spring容器导入了两个组件AutoProxyRegistrar, ProxyTransactionManagementConfiguration。

3、这两个组件AutoProxyRegistrar、ProxyTransactionManagementConfiguration实现了什么功能吗?

AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,该接口ImportBeanDefinitionRegistrar是一个接口,规定方法registerBeanDefinitions,返回值是空void。通过调用该方法自己给容器中添加组件。importingClassMetadata是当前类的注解信息,registry是bean定义的注册类,使用registry给容器注册一个bean实例。

AutoProxyRegistrar类给容器中注册了一个组件,InfrastructureAdvisorAutoProxyCreator(即基本的增强器自动代理创建组件)。分析InfrastructureAdvisorAutoProxyCreator既可以分析出AutoProxyRegistrar的功能了。

点进去看看,AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

InfrastructureAdvisorAutoProxyCreator的功能是什么呢,利用后置处理器机制对象创建以后,包装对象,返回一个代理对象(增强器)。代理对象执行方法利用拦截器链进行调用。

ProxyTransactionManagementConfiguration类是一个配置类,给容器中事务增强器BeanFactoryTransactionAttributeSourceAdvisor(transactionAdvisor),事务增强器要用事务注解的信息。

给容器中注册事务增强器,advisor.setTransactionAttributeSource(transactionAttributeSource());事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解。

给容器中注册事务增强器,advisor.setAdvice(transactionInterceptor());事务的拦截器,保存了事务的属性信息,包含了事务管理器。TransactionInterceptor的底层是MethodInterceptor即方法拦截器。什么是方法拦截器呢,比如给容器放入一个代理对象,代理对象要执行目标方法的时候,方法拦截器就会工作。

给容器中注册事务增强器,advisor.setTransactionAttributeSource(transactionAttributeSource());事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解。

return new AnnotationTransactionAttributeSource();点击进去,可以看到this.annotationParsers.add(new SpringTransactionAnnotationParser());该SpringTransactionAnnotationParser类解析事务注解的。

给容器中注册事务增强器,advisor.setAdvice(transactionInterceptor());事务的拦截器,保存了事务的属性信息,包含了事务管理器。TransactionInterceptor的底层是MethodInterceptor即方法拦截器。什么是方法拦截器呢,比如给容器放入一个代理对象,代理对象要执行目标方法的时候,方法拦截器就会工作。 

TransactionInterceptor interceptor = new TransactionInterceptor();类点进去。

MethodInterceptor在目标方法执行的时候,执行拦截器链,此时只有一个拦截器,即事务拦截器TransactionInterceptor。

该事务拦截器的功能,先获取事务相关的属性,再获取PlatformTransactionManager平台事务管理器,如果事先没有添加指定任何transactionManager,最终会从spring容器中按照类型进行获取一个PlatformTransactionManager。

执行目标方法,如果正常,利用事务管理器提交事务。

执行目标方法,如果异常,获取到事务管理器,利用事务管理器进行回滚此次操作,真正的回滚与提交是事务管理器进行操作的。MethodInterceptor只是对方法进行拦截。

4、事务控制的过程步骤,事务的执行流程和AOP的源码分析一致,首先使用注解@EnableTransactionManagement开启事务管理,然后使用AutoProxyRegistrar注册一个后置处理器InfrastructureAdvisorAutoProxyCreator,后置处理器负责包装代理对象。再注册ProxyTransactionManagementConfiguration一个配置类,配置类里面有AnnotationTransactionAttributeSource事务增强器(事务增强器要用事务注解的信息,解析事务的注解属性信息)、TransactionInterceptor事务拦截器,代理对象执行目标方法就会执行到当前容器里面拦截器链,每次执行如果异常利用事务管理器进行回滚操作,如果正常利用事务管理器,提交事务。

 

作者:别先生

博客园:https://www.cnblogs.com/biehongli/

如果您想及时得到个人撰写文章以及著作的消息推送,可以扫描上方二维码,关注个人公众号哦。

 

posted on 2019-12-29 14:11  别先生  阅读(757)  评论(0编辑  收藏  举报