【小家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这个增强器里,这个因为比价比较复杂,所以以一篇单独摘取出来详细讲解~~~请持续关注,就在下一篇哦~


相关文章
|
2月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
2月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
21天前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理
|
2月前
|
XML Java 数据格式
Spring5入门到实战------2、IOC容器底层原理
这篇文章深入探讨了Spring5框架中的IOC容器,包括IOC的概念、底层原理、以及BeanFactory接口和ApplicationContext接口的介绍。文章通过图解和实例代码,解释了IOC如何通过工厂模式和反射机制实现对象的创建和管理,以及如何降低代码耦合度,提高开发效率。
Spring5入门到实战------2、IOC容器底层原理
|
2月前
|
Java 程序员 数据库连接
女朋友不懂Spring事务原理,今天给她讲清楚了!
该文章讲述了如何解释Spring事务管理的基本原理,特别是针对女朋友在面试中遇到的问题。文章首先通过一个简单的例子引入了传统事务处理的方式,然后详细讨论了Spring事务管理的实现机制。
女朋友不懂Spring事务原理,今天给她讲清楚了!
|
2月前
|
XML Java 数据库
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
这篇文章是Spring5框架的实战教程,详细介绍了事务的概念、ACID特性、事务操作的场景,并通过实际的银行转账示例,演示了Spring框架中声明式事务管理的实现,包括使用注解和XML配置两种方式,以及如何配置事务参数来控制事务的行为。
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
|
2月前
|
Java Spring 开发者
掌握Spring事务管理,打造无缝数据交互——实用技巧大公开!
【8月更文挑战第31天】在企业应用开发中,确保数据一致性和完整性至关重要。Spring框架提供了强大的事务管理机制,包括`@Transactional`注解和编程式事务管理,简化了事务处理。本文深入探讨Spring事务管理的基础知识与高级技巧,涵盖隔离级别、传播行为、超时时间等设置,并介绍如何使用`TransactionTemplate`和`PlatformTransactionManager`进行编程式事务管理。通过合理设计事务范围和选择合适的隔离级别,可以显著提高应用的稳定性和性能。掌握这些技巧,有助于开发者更好地应对复杂业务需求,提升应用质量和可靠性。
34 0
|
7天前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
2月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
|
3月前
|
Java 测试技术 数据库
Spring Boot中的项目属性配置
本节课主要讲解了 Spring Boot 中如何在业务代码中读取相关配置,包括单一配置和多个配置项,在微服务中,这种情况非常常见,往往会有很多其他微服务需要调用,所以封装一个配置类来接收这些配置是个很好的处理方式。除此之外,例如数据库相关的连接参数等等,也可以放到一个配置类中,其他遇到类似的场景,都可以这么处理。最后介绍了开发环境和生产环境配置的快速切换方式,省去了项目部署时,诸多配置信息的修改。
下一篇
无影云桌面