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