Spring事务的开启原理详解

 更新时间:2021年03月22日 11:28:59   作者:柠檬时间  
这篇文章主要介绍了Spring事务的简单实现步骤,帮助大家更好的理解和学习使用spring,感兴趣的朋友可以了解下
  1. 在事务配置类上声明@EnableTransactionManagement注解开启事务
  2. 在事务配置类上定义数据源
  3. 在事务配置类上定义事务管理器
  4. 在相关类或者方法上使用@Transactional声明事务

代码如下:

@Configuration
@EnableTransactionManagement
public class RootConfig{
 
 @Bean
 public DataSource dataSource(){
  DruidDataSource dataSource = new DruidDataSource();
  dataSource.setXXX();
  ...
  
  return dataSource;
 }
 
 @Bean
 public PlatfromTransactionManager txManager(){
  return new DataSourceTransactionManager(dataSource());
 }
}
@Service
public class UserService{

 @Autowired
 private UserRepository userRepository;
 
 @Transactional
 public void addUser(User user){
  userRepository.save(user);
 }
}

@EnableTransactionManagement开启事务原理解析

@EnableTransactionManagement源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
 boolean proxyTargetClass() default false;
 AdviceMode mode() default AdviceMode.PROXY;
 int order() default Ordered.LOWEST_PRECEDENCE;
}

可以看到,@EnableTransactionManagement接口类主要Import了TransactionManagementConfigurationSelector来实现其注入,而TransactionManagementConfigurationSelector又主要使用selectImport方法来实现其注入,代码如下:

@Override
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
 Class<?> annoType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
 AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
 if (attributes == null) {
  throw new IllegalArgumentException(String.format(
   "@%s is not present on importing class '%s' as expected",
   annoType.getSimpleName(), importingClassMetadata.getClassName()));
 }

 AdviceMode adviceMode = attributes.getEnum(this.getAdviceModeAttributeName());
 //根据AdviceMode返回不同的类型,默认是AdviceMode.PROXY。
 String[] imports = selectImports(adviceMode);
 if (imports == null) {
  throw new IllegalArgumentException(String.format("Unknown AdviceMode: '%s'", adviceMode));
 }
 return imports;
}

@Override
protected String[] selectImports(AdviceMode adviceMode) {
 switch (adviceMode) {
  case PROXY:
   return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
  case ASPECTJ:
   return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
  default:
   return null;
 }
}

其中主要功能点为根据AdviceMode选择创建不同的bean,AdviceMode的默认代理方式是PROXY,jdk代理。所以返回的是AutoProxyRegistrar和ProxyTransactionManagementConfiguration。

我们先分析AutoProxyRegistrar,AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar,那在创建bean的时候会调用registerBeanDefinitions方法。registerBeanDefinitions方法的实现:

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
 boolean candidateFound = false;
 Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
 for (String annoType : annoTypes) {
  AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
  if (candidate == null) {
   continue;
  }
  Object mode = candidate.get("mode");
  Object proxyTargetClass = candidate.get("proxyTargetClass");
  if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
    Boolean.class == proxyTargetClass.getClass()) {
   candidateFound = true;
   //只有@EnableTransactionManagement注解才会走到这里
   if (mode == AdviceMode.PROXY) {
    AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
    if ((Boolean) proxyTargetClass) {
     AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
     return;
    }
   }
  }
 }
 //...
}

public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
 return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

可以看到,它通过注册InfrastructureAdvisorAutoProxyCreator来启动Spring Aop。

接下来再看ProxyTransactionManagementConfiguration的作用,代码如下:

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

 @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
  BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
  advisor.setTransactionAttributeSource(transactionAttributeSource());
  advisor.setAdvice(transactionInterceptor());
  advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
  return advisor;
 }

 @Bean
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public TransactionAttributeSource transactionAttributeSource() {
  return new AnnotationTransactionAttributeSource();
 }

 @Bean
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public TransactionInterceptor transactionInterceptor() {
  TransactionInterceptor interceptor = new TransactionInterceptor();
  interceptor.setTransactionAttributeSource(transactionAttributeSource());
  if (this.txManager != null) {
   interceptor.setTransactionManager(this.txManager);
  }
  return interceptor;
 }

}

ProxyTransactionManagementConfiguration是一个配置文件,注册了三个bean,BeanFactoryTransactionAttributeSourceAdvisor、AnnotationTransactionAttributeSource、TransactionInterceptor,而这三个类分别继承Advisor、Advice和Pointcut。即切面所需组件。

总结

@EnableTransactionManagement利用AutoProxyRegistrar启动Spring Aop,使用ProxyTransactionManagementConfiguration配置对应切面部件。

以上就是Spring事务的简单实现步骤的详细内容,更多关于Spring事务实现步骤的资料请关注脚本之家其它相关文章!

相关文章

  • SpringBoot版本升级容易遇到的一些问题

    SpringBoot版本升级容易遇到的一些问题

    由于项目需求,需要将nacos 1.4.6版本升级到2.x版本,由此引发的springboot、springcloud、springcloud Alibaba一系列版本变更,本文给大家总结一下SpringBoot版本升级容易遇到的一些问题,需要的朋友可以参考下
    2023-12-12
  • 基于springboot创建mybatis的完整步骤

    基于springboot创建mybatis的完整步骤

    MyBatis是一款优秀的数据库持久层框架,相比Hibernate我更喜欢使用MyBatis,看的到SQL还是让人更安心点,这篇文章主要给大家介绍了关于基于springboot创建mybatis的完整步骤,需要的朋友可以参考下
    2024-03-03
  • Java基础学习之集合底层原理

    Java基础学习之集合底层原理

    今天带大家回顾Java基础的相关知识,文中对集合底层原理作了非常详细的图文介绍,对Java初学者有非常好的帮助,需要的朋友可以参考下
    2021-05-05
  • Java操作ElasticSearch的实例详解

    Java操作ElasticSearch的实例详解

    Elasticsearch 是一个分布式的搜索和分析引擎,广泛用于全文搜索、日志分析等场景,本文将介绍如何在 Java 应用中使用 Elasticsearch 客户端来连接和操作 Elasticsearch 集群,希望对大家有所帮助
    2025-01-01
  • JDBC编程实现文件、图片的存储方法

    JDBC编程实现文件、图片的存储方法

    这篇文章主要介绍了JDBC编程实现文件、图片的存储方法,以实例形式分析了Java基于JDBC操作数据库的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-10-10
  • java数组元素的引用实例讲解

    java数组元素的引用实例讲解

    在本篇文章里小编给大家整理的是一篇关于java数组元素的引用实例讲解内容,有需要的朋友们可以学习参考下。
    2021-03-03
  • Java线程阻塞方法sleep()与wait()的全面讲解

    Java线程阻塞方法sleep()与wait()的全面讲解

    这篇文章主要介绍了Java线程阻塞方法sleep()与wait()的全面讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • 你一定不知道的Java Unsafe用法详解

    你一定不知道的Java Unsafe用法详解

    Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,下面这篇文章主要给大家介绍了关于Java Unsafe用法的相关资料,需要的朋友可以参考下
    2021-10-10
  • java图形化界面实现简单混合运算计算器的示例代码

    java图形化界面实现简单混合运算计算器的示例代码

    这篇文章主要介绍了java图形化界面实现简单混合运算计算器的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • java性能调优System的gc垃圾回收方法

    java性能调优System的gc垃圾回收方法

    这篇文章主要为大家介绍了java性能调优System的gc垃圾回收方法示例解析有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03

最新评论