Spring源码解析之事务管理

一、环境准备

基本步骤
1)引入mysql驱动,Druid连接池,jdbc依赖
2)配置类TxConfig, 注册JdbcTemplate, DruidDataSource
3)编写业务类,使用原生jdbc操作数据库
4)加入事务管理
     @EnableTransactionManagement
     @Transactional
   注册事务管理器TransactionManager
5)调试实现回滚,int tem = 10 / 0;
  当数据回滚时候,数据库自增主键会继续增长,即回滚时数据库主键也会自增

1、引入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.18</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.3.RELEASE</version>
    </dependency>
</dependencies>

2、配置类TxConfig

@EnableTransactionManagement
@ComponentScan(basePackages = {"com.whf.spring.tx"})
@Configuration
public class TxConfig {
    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/demo");
        dataSource.setUsername("root");
        dataSource.setPassword("admin");
        return dataSource;
    }
    @Bean
    public JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(dataSource());
    }
    @Bean
    public TransactionManager transactionManager() {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource());
        return transactionManager;
    }

}

3、编写业务调试

service类

@Service
public class UserService{
    @Autowired
    private UserDao userDao;

    @Transactional
    @Override
    public int save(User user) {
        int count = userDao.save(user);
        if (count > 0) {
            System.out.println("成功插入数据库。。。。");
        } else {
            System.out.println("插入失败。。。。");
        }
        int tem = 10 / 0;
        return count;
    }
}

dao类

@Repository
public class UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public int save(User user) {
        String sql = "insert into `user`(name, age) values(?, ?)";
        int count = jdbcTemplate.update(sql, user.getName(), user.getAge());
        return count;
    }
}    

调试类(执行结果报错,并且数据没有插入新数据则代表事务成功回滚)

public class TxDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
        UserService userService = (UserService) context.getBean(UserService.class);
        int ret = userService.save(new User(UUID.randomUUID().toString().substring(0, 5), 18));
        System.out.println(ret);
    }
}
// 报错,并且数据库没有新增则证明事务起作用了
Exception in thread "main" java.lang.ArithmeticException: / by zero

二、源码解析

1、从@EnableTransactionManagement开始分析

1、@EnableTransactionManagement
  // 引入TransactionManagementConfigurationSelector
  1)@Import({TransactionManagementConfigurationSelector.class})
  2)TransactionManagementConfigurationSelector实现了ImportSelector.selectImports(AdviceMode adviceMode)
    通过ImportSelector注册了两个类AutoProxyRegistrar和ProxyTransactionManagementConfiguration
    return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};

2、AutoProxyRegistrar和ProxyTransactionManagementConfiguration类结构分析
  1)AutoProxyRegistrar implements ImportBeanDefinitionRegistrar   
   在实现方法registerBeanDefinitions中注册了一个bean
   internalAutoProxyCreator => InfrastructureAdvisorAutoProxyCreator  
   后续再详细说InfrastructureAdvisorAutoProxyCreator,跟AOP代理基本是一样的原理 
  2)ProxyTransactionManagementConfiguration
      AbstractTransactionManagementConfiguration
        ImportAware
          Aware
     在beam初始化之前由beanPostProcessor设置一些元信息
     ((ImportAware) bean).setImportMetadata(importingClass);   
// 后续着重分析InfrastructureAdvisorAutoProxyCreator  

2、分析InfrastructureAdvisorAutoProxyCreator

1、分析类结构
InfrastructureAdvisorAutoProxyCreator
  AbstractAdvisorAutoProxyCreator
    AbstractAutoProxyCreator extends ProxyProcessorSupport (实现Ordered接口)
      implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
2、分析SmartInstantiationAwareBeanPostProcessor和BeanFactoryAware
    1)SmartInstantiationAwareBeanPostProcessor
      InstantiationAwareBeanPostProcessor
        BeanPostProcessor
    可见InfrastructureAdvisorAutoProxyCreator是一个BeanPostProcessor,具体实现是在
    父类的AbstractAutoProxyCreator
    2)BeanFactoryAware
         Aware
       在refresh方法中的初始化其余非懒加载单实例bean方法中给bean注入BeaFactory,调用栈如下
       doCreateBean(beanName, mbdToUse, args); 
         initializeBean(beanName, exposedObject, mbd);
           invokeAwareMethods(beanName, bean);
             ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);

3、AbstractAutoProxyCreator

从上面可以看出InfrastructureAdvisorAutoProxyCreator 是一个BeanPostProcessor。那么可以从其父类AbstractAutoProxyCreator实现的BeanPostProcessor切入分析

1、再次看下该类结构
AbstractAutoProxyCreator 
  SmartInstantiationAwareBeanPostProcessor
    InstantiationAwareBeanPostProcessor
      BeanPostProcessor
可以发现核心逻辑在下面两个BeanPostProcessor的方法中,
接下来就可以根据AbstractAutoProxyCreator的这个方法的具体实现进行分析
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
BeanPostProcessor.postProcessAfterInitialization()

4、分析AbstractAutoProxyCreator方法

上面分析的两个方法打上断点debug,postProcessBeforeInstantiation和postProcessAfterInitialization方法

1、先进入postProcessBeforeInstantiation方法
  1)在创建bean实例之前先调用下面方法,给BeanPostProcessor一个机会返回一个代理对象,
  也就是通过InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
  resolveBeforeInstantiation(beanName, mbdToUse);
    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
      if (bp instanceof InstantiationAwareBeanPostProcessor)  // 类型判断
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
   2)分析AbstractAutoProxyCreator.postProcessBeforeInstantiation()
   // 判断是否已经进行增强处理
   this.advisedBeans.containsKey(cacheKey)
   // 是否基本类型(Advice、Pointcut、Advisor、AopInfrastructureBean)
   isInfrastructureClass(beanClass) 
   // 判断是否跳过此增强逻辑
   shouldSkip(Class<?> beanClass, String beanName)
     // 确定给定的bean名称是否表示“原始实例”
     AutoProxyUtils.isOriginalInstance(beanName, beanClass); 
   // 如果我们有一个自定义的TargetSource,在这里创建代理。
   // 禁止对目标bean进行不必要的默认实例化:TargetSource将以自定义方式处理目标实例  
   TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
   上面返回的是 targetSource = null,这个方法到这里就直接返回null结束了。

2、进入postProcessAfterInitialization方法    
  // 此时bean已经实例化并且已经完成了初始化,判断是否需要包装成代理bean
  wrapIfNecessary(bean, beanName, cacheKey);
  1) 获取增强拦截器
  getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); 
    // 查找可用增强器
    findEligibleAdvisors(beanClass, beanName);
      // 查找所有候选增强器
      findCandidateAdvisors();
      // 查找能用到当前bean的增强器
      findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); 
最终找到的是BeanFactoryTransactionAttributeSourceAdvisor,
父类有个Advice属性:private transient volatile Advice advice;
BeanFactoryTransactionAttributeSourceAdvisor中的advice为TransactionInterceptor类型
TransactionInterceptor implements MethodInterceptor(方法拦截器)

  2)创建代理对象
  Object proxy = createProxy(
      bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  // 从beanFactory获取该bean定义,标记为
  if (this.beanFactory instanceof ConfigurableListableBeanFactory)
  AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    // ORIGINAL_TARGET_CLASS_ATTRIBUTE : org.springframework.aop.framework.autoproxy.AutoProxyUtils.originalTargetClass            
    beanFactory.getMergedBeanDefinition(beanName).setAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE, targetClass);        
  
  // 创建代理工厂
  ProxyFactory proxyFactory = new ProxyFactory();
  // 获取增强器BeanFactoryTransactionAttributeSourceAdvisor
  Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);    
  // 配置增强器到代理工厂
  proxyFactory.addAdvisors(advisors);  
  // 获取代理对象
  proxyFactory.getProxy(getProxyClassLoader());
    createAopProxy().getProxy(classLoader);
      // 根据是否实现接口创建JDK动态代理或Cglib动态代理
      createAopProxy() => new JdkDynamicAopProxy(config);
      // 通过JDK动态代理创建代理对象
      JdkDynamicAopProxy.getProxy(classLoader) => Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
JdkDynamicAopProxy实现了InvocationHandler方法,在代理类执行时,最终会会执行JdkDynamicAopProxy.invoke(Object proxy, Method method, Object[] args)      

5、调用代理方法

上面流程已经完成了UserService代理对象的创建,从容器中取出bean代理对象,调用标记了

@Transactional的save(User user),在调用处打上断点

1、调用代理方法(InvocationHandler.invoke())
JdkDynamicAopProxy.invoke(Object proxy, Method method, Object[] args)
1) 判断是否equals方法或hashCode方法,是的话直接执行方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
   // The target does not implement the equals(Object) method itself.
   return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
   // The target does not implement the hashCode() method itself.
   return hashCode();
}

2)判断Mehod的Class对象是否接口或者Advised类型
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
      method.getDeclaringClass().isAssignableFrom(Advised.class)) {
   // Service invocations on ProxyConfig with the proxy config...
   return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}

3)获取代理增强拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
也就是之前分析的BeanFactoryTransactionAttributeSourceAdvisor

// 封装成MehtodInvocation对象并执行proceed方法
MethodInvocation invocation =
      new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();

4)proceed方法
// 迭代拦截器链获取拦截器知道,直到结果为-1代表全部都已找出,从最后一个开始往前执行拦截器
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
   return invokeJoinpoint();
}
// 获取拦截器
Object interceptorOrInterceptionAdvice =
      this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 调用方法拦截器的invoke方法
((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)

// 执行TransactionInterceptor拦截器(实现了MethodInterceptor接口),事务调用方法
invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);

// 获取事务属性和事务管理器
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final TransactionManager tm = determineTransactionManager(txAttr);

// 创建事务
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
  // 创建事务信息对象
  TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
    // 将事务信息绑定到当前线程中ThreadLocal
    txInfo.bindToThread();

// 执行代理事务方法,如果抛异常则回滚,正常则清除事务信息,最后在方法返回时提交事务
try {
   // This is an around advice: Invoke the next interceptor in the chain.
   // This will normally result in a target object being invoked.
   retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
   // target invocation exception
   completeTransactionAfterThrowing(txInfo, ex);
   throw ex;
}
finally {
   cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);

6、事务回滚分析

completeTransactionAfterThrowing(txInfo, ex);
  // 判断事务该异常是否回滚
  txInfo.transactionAttribute.rollbackOn(ex)
  // 如果@Transactional注解没有配置异常回滚属性,则RuntimeException和Error类型异常都回滚
  (ex instanceof RuntimeException || ex instanceof Error);
  // 通过事务管理器进行回滚
  txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
    processRollback(defStatus, false);
      doRollback(status);
        // 事务管理器获取Connection对象调用rollback方法进行回滚
        DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction();
        Connection con = txObject.getConnectionHolder().getConnection();
        con.rollback();

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值