五.Spring之声明式事务原理

需要了解@Import注解的应用https://blog.csdn.net/u014203449/article/details/86559350

后置处理器https://blog.csdn.net/u014203449/article/details/86665963

代理模式和方法拦截器https://blog.csdn.net/u014203449/article/details/105707730

一.演示案例

 环境搭建:
  1、导入相关依赖
          数据源、数据库驱动、Spring-jdbc模块
  2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据
  3、给方法上标注 @Transactional 表示当前方法是一个事务方法;
  4、 @EnableTransactionManagement 开启基于注解的事务管理功能;
          @EnableXXX
  5、配置事务管理器来控制事务;
          @Bean
          public PlatformTransactionManager transactionManager()

@EnableTransactionManagement
@ComponentScan("com.atguigu.tx")
@Configuration
public class TxConfig {
	
	//数据源
	@Bean
	public DataSource dataSource() throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser("wisdomclass");
		dataSource.setPassword("susOn@20190916");
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl("jdbc:mysql://xxxx:3306/intelligent_admin");
		return dataSource;
	}
	
	//
	@Bean
	public JdbcTemplate jdbcTemplate() throws Exception{
		//Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
		return jdbcTemplate;
	}
	
	//注册事务管理器在容器中
	@Bean
	public PlatformTransactionManager transactionManager() throws Exception{
		return new DataSourceTransactionManager(dataSource());
	}
	

}

service,发生一次异常

@Service
public class UserService {
	
	@Autowired
	private UserDao userDao;
	
	@Transactional
	public void insertUser(){
		userDao.insert();
		//otherDao.other();xxx
		System.out.println("插入完成...");
		int i = 10/0;
	}

}

dao ,保存一条数据

@Repository
public class UserDao {
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	public void insert(){
		String sql = "INSERT INTO `user_info`(`name`,sex) VALUES(?,?)";
		String username = UUID.randomUUID().toString().substring(0, 5);
		jdbcTemplate.update(sql, username,1);
		
	}

}

单元测试

	@Test
	public void test01(){
		AnnotationConfigApplicationContext applicationContext = 
				new AnnotationConfigApplicationContext(TxConfig.class);
	
		UserService userService = applicationContext.getBean(UserService.class);
		
		userService.insertUser();
		applicationContext.close();
	}

结果sql执行新增过后, 数据库数据没有变化,因为异常导致事务回滚。

二.@EnableTransactionManagement

和AOP 的@Enable注解一样,看看它给容器注入了什么?

TransactionManagementConfigurationSelector,实现了ImportSelector接口,就看 selectImports方法的返回结果是什么,就会往容器中注入什么组件。

根据adviceMode的值去注入不同的组件。

adviceMode的值在 EnableTransactionManagement 中 默认为 AdviceMode.PROXY,所以会注入 AutoProxyRegistrar 和ProxyTransactionManagementConfiguration。

proxyTargetClass ,默认值为false,一会用到。

1.AutoProxyRegistrar

实现了 ImportBeanDefinitionRegistrar接口,可以用 BeanDefinitionRegistry 自定义往容器中注册组件。

可以打断点看看:

1.importingClassMetadata.getAnnotationTypes(); 得到一些标注的注解,并遍历

2.AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);得到注解的属性

3.如果注解的mode属性值不为空,且属性proxyTargetClass不为空,且...符合后面的条件,最终会执行AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

而proxyTargetClass ,默认值为false,forceAutoProxy不会执行。

 会往容器中注入InfrastructureAdvisorAutoProxyCreator 实例

InfrastructureAdvisorAutoProxyCreator看继承关系,和AOP的AnnotationAwareAspectJAutoProxyCreator很像,是个BeanPostProcessor。

没有找到InfrastructureAdvisorAutoProxyCreator重写postProcessAfterInitialization等后置处理的方法,说明它的功能和AbstractAutoProxyCreator一样,如下和AOP一样。

打断点,查看userService的初始化(事务注解写在了userService上),

会发现它有个增强器,最终会返回userService的代理对象。

跟AOP一样,利用代理、增强器对原方法加强。

2.ProxyTransactionManagementConfiguration

给容器注入BeanFactoryTransactionAttributeSourceAdvisor,TransactionAttributeSource(解析事务注解的属性),

TransactionInterceptor(方法拦截器)

 

TransactionInterceptor实现了MethodInterceptor,是个方法拦截器,在给userservice创建代理后,调用userService的方法时,会先执行它的invoke方法。

在单元测试调用userService保存时,打断点,看看流程。

进入断点,和AOP一样,进入了CglibAopProxy的intercept方法。

得到方法连接器链chain中有一个元素,就是TransactionInterceptor

最后构造 CglibMethodInvocation 执行proceed方法。

执行proceed方法,断点进入ReflectiveMethodInvocation的proceed

再进入断点,就来到了TransactionInterceptor 的invoke

invokeWithinTransaction方法:根据方法名来看看

1)、先获取事务相关的属性 getTransactionAttribute


  2)、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger,最终会从容器中按照类型获取一个PlatformTransactionManager;
3)、事务执行

    创建事务(createTransactionIfNecessary)

              --->执行目标方法(invocation.proceedWithInvocation())

                  ----->如果异常,获取到事务管理器,利用事务管理回滚操作(completeTransactionAfterThrowing(txInfo, ex));
                  ----->如果正常,利用事务管理器,提交事务(commitTransactionAfterReturning(txInfo))


 

猜你喜欢

转载自blog.csdn.net/u014203449/article/details/105768424