欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring源码解析之事务管理

程序员文章站 2022-07-05 18:10:15
...

一、环境准备

基本步骤
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();

相关标签: Spring