天天看点

spring注解驱动(声明式事务):简单使用,原码解析,AutoProxyRegistrar,ProxyTransactionManagementConfiguration

简单使用

配置类

package jane.tx;

import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/*
 * 声明式事务:
 * 环境搭建:
 * 1.导入相关的依赖:数据源,数据库驱动,spring-jdbc模块
 * 2.配置数据源,JdbcTemplate操作数据
 * 3.给方法上标注@Transactional,表示当前是一个事务方法
 * 4.@EnableTransactionManagement开启基于注解的事务管理功能
 */
@EnableTransactionManagement
@ComponentScan({"jane.tx"})
@Configuration
public class MyConfigOftx
{
  //数据源
  @Bean
  public DataSource dataSource() throws Exception
  {
    ComboPooledDataSource dataSource = new ComboPooledDataSource();
    dataSource.setUser("root");
    dataSource.setPassword("1234");
    dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
    dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8");
    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());
  }
}      

Dao和Service

package jane.tx;

import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDao
{
  @Autowired
  JdbcTemplate jdbcTemplate;
  public void insert()
  {
    String sql="insert into user (name ,age) values (?,?)";
    String name = UUID.randomUUID().toString().substring(0, 5);
    jdbcTemplate.update(sql,name,18 );
  }
}      
package jane.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService
{
  @Autowired
  UserDao userDao;
  
  @Transactional
  public void insertUser()
  {
    userDao.insert();
    System.out.println("插入成功");
    int i=10/0;
  }
}      
@Test
  public void testTX()
  {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfigOftx.class);
    UserService userService = applicationContext.getBean(UserService.class);
    JdbcTemplate bean = applicationContext.getBean(JdbcTemplate.class);
    System.out.println(bean);
    System.out.println(userService);
    userService.insertUser();
    System.out.println("容器关闭");
    applicationContext.close();
  }      

原码解析

点进@EnableTransactionManagement查看

​@Import(TransactionManagementConfigurationSelector.class)​

​ 里面导入了一个Selector

spring注解驱动(声明式事务):简单使用,原码解析,AutoProxyRegistrar,ProxyTransactionManagementConfiguration

利用TransactionManagementConfigurationSelector给容器中导入组件

看AdviceMode的属性导入不同的组件,看上面的一张截图

AdviceMode mode() default AdviceMode.PROXY;默认是PROXY

所以就会导入两个组件

​AutoProxyRegistrar​

​​

​ProxyTransactionManagementConfiguration​

spring注解驱动(声明式事务):简单使用,原码解析,AutoProxyRegistrar,ProxyTransactionManagementConfiguration

AutoProxyRegistrar

点进去AutoProxyRegistrar,它也是给容器注册组件的

spring注解驱动(声明式事务):简单使用,原码解析,AutoProxyRegistrar,ProxyTransactionManagementConfiguration

点进AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

注册了一个​

​InfrastructureAdvisorAutoProxyCreator的组件​

​​ 你看下面的​

​AnnotationAwareAspectJAutoProxyCreator​

​,这不是AOP时候注册的组件吗?

InfrastructureAdvisorAutoProxyCreator和之前的AOP一样,也是一个后置处理器

spring注解驱动(声明式事务):简单使用,原码解析,AutoProxyRegistrar,ProxyTransactionManagementConfiguration

InfrastructureAdvisorAutoProxyCreator

点进​

​InfrastructureAdvisorAutoProxyCreator​

​查看

可以发现它没干什么,主要是利用后置处理器机制在创建对象之后包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用

spring注解驱动(声明式事务):简单使用,原码解析,AutoProxyRegistrar,ProxyTransactionManagementConfiguration

ProxyTransactionManagementConfiguration

点进​

​ProxyTransactionManagementConfiguration​

​ 给容器注册了事务增强器,

事务增强器需要一个​

​transactionAttributeSource()​

事务注解信息,解析事务注解

这个对象是AnnotationTransactionAttributeSource();

它是SpringTransactionAnnotationParser(spring的解析器)

JtaTransactionAnnotationParser(Jta解析器)

Ejb3TransactionAnnotationParser(Ejb3解析器)

这些解析器主要是解析注解能写的属性

spring注解驱动(声明式事务):简单使用,原码解析,AutoProxyRegistrar,ProxyTransactionManagementConfiguration
spring注解驱动(声明式事务):简单使用,原码解析,AutoProxyRegistrar,ProxyTransactionManagementConfiguration
spring注解驱动(声明式事务):简单使用,原码解析,AutoProxyRegistrar,ProxyTransactionManagementConfiguration

事务增强器还需要一个事务拦截器​

​transactionInterceptor()​

TransactionInterceptor保存了事务属性信息和事务管理器

点进TransactionInterceptor,发现它是一个MethodInterceptor,AOP的时候所有的增强器都会包装成MethodInterceptor

​public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {​

spring注解驱动(声明式事务):简单使用,原码解析,AutoProxyRegistrar,ProxyTransactionManagementConfiguration

进入TransactionInterceptor,invoke()方法的

​return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback()​

​方法首先执行拦截器链,拦截器链里面就只有TransactionInterceptor一个拦截器

事务拦截器工作流程:

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

2)再获取PlatformTransactionManager,如果事先没有指定任何的TransactionManager

最终会从容器中按照类型获取一个PlatformTransactionManager

3)执行目标方法

如果异常,获取事务管理器,利用事务管理器回滚

如果正常利用事务管理器提交事务

spring注解驱动(声明式事务):简单使用,原码解析,AutoProxyRegistrar,ProxyTransactionManagementConfiguration
spring注解驱动(声明式事务):简单使用,原码解析,AutoProxyRegistrar,ProxyTransactionManagementConfiguration