【小家Spring】从基于@Transactional全注解方式的声明式事务入手,彻底掌握Spring事务管理的原理(中)

简介: 【小家Spring】从基于@Transactional全注解方式的声明式事务入手,彻底掌握Spring事务管理的原理(中)

ProxyTransactionManagementConfiguration


它是一个@Configuration,所以看看它向容器里注入了哪些Bean


@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
  // 这个Advisor可是事务的核心内容。。。。。也是本文重点分析的对象
  @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
    BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
    advisor.setTransactionAttributeSource(transactionAttributeSource());
    advisor.setAdvice(transactionInterceptor());
    // 顺序由@EnableTransactionManagement注解的Order属性来指定 默认值为:Ordered.LOWEST_PRECEDENCE
    if (this.enableTx != null) {
      advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
    }
    return advisor;
  }
  // TransactionAttributeSource 这种类特别像 `TargetSource`这种类的设计模式
  // 这里直接使用的是AnnotationTransactionAttributeSource  基于注解的事务属性源~~~
  @Bean
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public TransactionAttributeSource transactionAttributeSource() {
    return new AnnotationTransactionAttributeSource();
  }
  // 事务拦截器,它是个`MethodInterceptor`,它也是Spring处理事务最为核心的部分
  // 请注意:你可以自己定义一个TransactionInterceptor(同名的),来覆盖此Bean(注意是覆盖)
  // 另外请注意:你自定义的BeanName必须同名,也就是必须名为:transactionInterceptor  否则两个都会注册进容器里面去~~~~~~
  @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;
  }
}
// 父类(抽象类)  它实现了ImportAware接口  所以拿到@Import所在类的所有注解信息
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
  @Nullable
  protected AnnotationAttributes enableTx;
  /**
   * Default transaction manager, as configured through a {@link TransactionManagementConfigurer}.
   */
  // 此处:注解的默认的事务处理器(可议通过实现接口TransactionManagementConfigurer来自定义配置)
  // 因为事务管理器这个东西,一般来说全局一个就行,但是Spring也提供了定制化的能力~~~
  @Nullable
  protected PlatformTransactionManager txManager;
  @Override
  public void setImportMetadata(AnnotationMetadata importMetadata) {
    // 此处:只拿到@EnableTransactionManagement这个注解的就成~~~~~ 作为AnnotationAttributes保存起来
    this.enableTx = AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
    // 这个注解是必须的~~~~~~~~~~~~~~~~
    if (this.enableTx == null) {
      throw new IllegalArgumentException("@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
    }
  }
  // 这里和@Async的处理一样,配置文件可以实现这个接口。然后给注解驱动的给一个默认的事务管理器~~~~
  // 设计模式都是想通的~~~
  @Autowired(required = false)
  void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
    if (CollectionUtils.isEmpty(configurers)) {
      return;
    }
    // 同样的,最多也只允许你去配置一个~~~
    if (configurers.size() > 1) {
      throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
    }
    TransactionManagementConfigurer configurer = configurers.iterator().next();
    this.txManager = configurer.annotationDrivenTransactionManager();
  }
  // 注册一个监听器工厂,用以支持@TransactionalEventListener注解标注的方法,来监听事务相关的事件
  // 后面会专门讨论,通过事件监听模式来实现事务的监控~~~~
  @Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
    return new TransactionalEventListenerFactory();
  }
}


关于事务相关的基础类打点,建议先参阅:

【小家Spring】Spring事务相关的基础类打点(spring-jdbc和spring-tx两个jar),着重讲解AnnotationTransactionAttributeSource


下面重中之重来了,那就是BeanFactoryTransactionAttributeSourceAdvisor这个增强器


BeanFactoryTransactionAttributeSourceAdvisor


首先看它的父类:AbstractBeanFactoryPointcutAdvisor这个之前在讲述AOP的时候已经大篇幅解释过:

【小家Spring】Spring AOP之Advisor、PointcutAdvisor、IntroductionAdvisor、IntroductionInterceptor(引介增强)

父类是一个和Bean工厂有关的Advisor。


再看自己,它是一个和Bean工厂和事务都有关系的Advisor


从上面的配置类可议看出,它是new出来一个。

使用的Advice为:advisor.setAdvice(transactionInterceptor()),既容器内的事务拦截器~~~~

使用的事务属性源为:advisor.setTransactionAttributeSource(transactionAttributeSource()),既一个new AnnotationTransactionAttributeSource()支持三种事务注解来标注~~~

// @since 2.5.5
// 它是一个AbstractBeanFactoryPointcutAdvisor ,关于这个Advisor 请参阅之前的博文讲解~~~
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
  @Nullable
  private TransactionAttributeSource transactionAttributeSource;
  // 这个很重要,就是切面。它决定了哪些类会被切入,从而生成的代理对象~ 
  // 关于:TransactionAttributeSourcePointcut 下面有说~
  private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
    // 注意此处`getTransactionAttributeSource`就是它的一个抽象方法~~~
    @Override
    @Nullable
    protected TransactionAttributeSource getTransactionAttributeSource() {
      return transactionAttributeSource;
    }
  };
  // 可议手动设置一个事务属性源~
  public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
    this.transactionAttributeSource = transactionAttributeSource;
  }
  // 当然我们可以指定ClassFilter  默认情况下:ClassFilter classFilter = ClassFilter.TRUE;  匹配所有的类的
  public void setClassFilter(ClassFilter classFilter) {
    this.pointcut.setClassFilter(classFilter);
  }
  // 此处pointcut就是使用自己的这个pointcut去切入~~~
  @Override
  public Pointcut getPointcut() {
    return this.pointcut;
  }
}


下面当然要重点看看TransactionAttributeSourcePointcut,它是怎么切入的


TransactionAttributeSourcePointcut


这个就是事务的匹配Pointcut切面,决定了哪些类需要生成代理对象从而应用事务。


// 首先它的访问权限事default 显示是给内部使用的
// 首先它继承自StaticMethodMatcherPointcut   所以`ClassFilter classFilter = ClassFilter.TRUE;` 匹配所有的类
// 并且isRuntime=false  表示只需要对方法进行静态匹配即可~~~~
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
  // 方法的匹配  静态匹配即可(因为事务无需要动态匹配这么细粒度~~~)
  @Override
  public boolean matches(Method method, Class<?> targetClass) {
    // 实现了如下三个接口的子类,就不需要被代理了  直接放行
    // TransactionalProxy它是SpringProxy的子类。  如果是被TransactionProxyFactoryBean生产出来的Bean,就会自动实现此接口,那么就不会被这里再次代理了
    // PlatformTransactionManager:spring抽象的事务管理器~~~
    // PersistenceExceptionTranslator对RuntimeException转换成DataAccessException的转换接口
    if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
        PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
        PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
      return false;
    }
    // 重要:拿到事务属性源~~~~~~
    // 如果tas == null表示没有配置事务属性源,那是全部匹配的  也就是说所有的方法都匹配~~~~(这个处理还是比较让我诧异的~~~)
    // 或者 标注了@Transaction这样的注解的方法才会给与匹配~~~
    TransactionAttributeSource tas = getTransactionAttributeSource();
    return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
  } 
  ...
  // 由子类提供给我,告诉事务属性源~~~~ 我才好知道哪些方法我需要切嘛~~~
  @Nullable
  protected abstract TransactionAttributeSource getTransactionAttributeSource();
}


关于matches方法的调用时机:只要是容器内的每个Bean,都会经过AbstractAutoProxyCreator#postProcessAfterInitialization从而会调用wrapIfNecessary方法,因此容器内所有的Bean的所有方法在容器启动时候都会执行此matche方法,因此请注意缓存的使用~~~~~


这样结合这篇博文:

【小家Spring】Spring事务相关的基础类打点(spring-jdbc和spring-tx两个jar),着重讲解AnnotationTransactionAttributeSource

就能知道Spring最终会给哪些类生成代理对象,事务可以作用在哪些方法上~~~~


真正的执行事务方法,还是在TransactionInterceptor这个增强器里,这个因为比价比较复杂,所以以一篇单独摘取出来详细讲解~~~请持续关注,就在下一篇哦~


相关文章
|
3天前
|
SQL Java 关系型数据库
【SpringFramework】Spring事务
本文简述Spring中数据库及事务相关衍伸知识点。
34 9
|
11天前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
41 13
|
1月前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
49 2
Spring高手之路26——全方位掌握事务监听器
|
1月前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
2月前
|
Java 开发者 Spring
Spring高手之路24——事务类型及传播行为实战指南
本篇文章深入探讨了Spring中的事务管理,特别是事务传播行为(如REQUIRES_NEW和NESTED)的应用与区别。通过详实的示例和优化的时序图,全面解析如何在实际项目中使用这些高级事务控制技巧,以提升开发者的Spring事务管理能力。
64 1
Spring高手之路24——事务类型及传播行为实战指南
|
2月前
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
|
2月前
|
XML Java 数据库连接
Spring中的事务是如何实现的
Spring中的事务管理机制通过一系列强大的功能和灵活的配置选项,为开发者提供了高效且可靠的事务处理手段。无论是通过注解还是AOP配置,Spring都能轻松实现复杂的事务管理需求。掌握这些工具和最佳实践,能
80 3
|
5月前
|
XML Java 数据库
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
这篇文章是Spring5框架的实战教程,详细介绍了事务的概念、ACID特性、事务操作的场景,并通过实际的银行转账示例,演示了Spring框架中声明式事务管理的实现,包括使用注解和XML配置两种方式,以及如何配置事务参数来控制事务的行为。
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
|
7月前
|
XML Java 数据库
Spring5系列学习文章分享---第五篇(事务概念+特性+案例+注解声明式事务管理+参数详解 )
Spring5系列学习文章分享---第五篇(事务概念+特性+案例+注解声明式事务管理+参数详解 )
38 0
|
Java 数据库连接 API
请解释Spring中的声明式事务管理是如何工作的?
在Spring框架中,声明式事务管理是通过使用AOP(面向切面编程)和事务拦截器来实现的。声明式事务管理允许开发者通过在方法或类级别上添加注解来定义事务的行为,而无需显式地编写事务管理的代码。
请解释Spring中的声明式事务管理是如何工作的?
下一篇
开通oss服务