当前位置: 首页 > java >正文

【Spring底层分析】Spring AOP补充以及@Transactional注解的底层原理分析

这篇文章主要是针对源码进行总结,如果想看源码可以移步到另外一篇文章:https://blog.csdn.net/m0_73866527/article/details/148384920?spm=1001.2014.3001.5501

一、AOP底层原理补充

1、@EnableAspectJAutoProxy,依赖springboot自动装配原理。

项目中引入了 Spring Boot 的 依赖比如spring-boot-starter-web,这个依赖间接引入了 spring-boot-autoconfigure 这个JAR包,这个JAR包里的 META-INF下的文件中,定义了一长串自动配置类,其中就包括:

org.springframework.boot.autoconfigure.aop.AopAutoConfiguration

当springboot启动后,会扫描这个文件里定义的每个类,当处理到AopAutoConfiguration这个类时,做了以下事:

  • 这个类上有一个条件注解 @ConditionalOnClass(Advice.class),由于Starter引入了AOP包,这个条件百分百满足。
  • AopAutoConfiguration 内部使用了一个关键注解 @EnableAspectJAutoProxy。这个注解的作用,就是向Spring容器注册 AnnotationAwareAspectJAutoProxyCreator 的Bean定义。
@AutoConfiguration
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {@Configuration(proxyBeanMethods = false)@ConditionalOnClass(Advice.class)static class AspectJAutoProxyingConfiguration {@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = false) // 看这里!@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")static class JdkDynamicAutoProxyConfiguration {}@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = true) // 看这里!@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)static class CglibAutoProxyConfiguration {}}// ... 其他配置
}

总结:@EnableAspectJAutoProxy -> 作用是向spring容器中注册AnnotationAwareAspectJAutoProxyCreator后置处理器的bean定义。
(以上代码可以发现有个熟悉字眼:jdk、cglib,这里挖个坑,我们下次来学习这两种代理方式~)

2、spring容器启动后,流程是:

  • 扫描指定包路径下的注解,然后将被注解标识的类信息保存到bean定义中

  • 注册所有后置处理器到容器中

  • 注册所有非懒加载单实例bean

3、注册所有单实例bean的流程:

  • 实例化
  • 属性赋值
  • 初始化

4、在初始化之前,会遍历所有后置处理器执行postProcessBeforeInstantiation方法。这里我们具体介绍AnnotationAwareAspectJAutoProxyCreator.postProcessBeforeInstantiation:

  • 遍历容器中所有已注册的Bean定义
  • 找出被 @Aspect 注解标注的类
  • 解析这个类上的所有增强方法,将切入点、增强方法、增强类型缓存起来。

5、初始化之后,会遍历所有后置处理器执行postProcessAfterInitialization方法。这里我们具体介绍AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization:

  • 查找基础设施Advisor:比如已经存在于容器中的 TransactionAdvisor

  • 构建 并 返回自定义的AspectJ Advisor:

    • 遍历容器中所有已经实例化好的单例Bean,对于那些被 @Aspect 注解标注的Bean,会根据之前缓存起来的切面类元数据创建出一个个增强器,一个增强器里包含一个增强方法和pointcut切入点表达式的信息。这些增强器会被缓存起来,用于是否创建代理对象的判断。

    至此,我们得到了一个包含“基础设施 Advisor”和“所有自定义 AspectJ Advisor”的完整候选列表。

  • 筛选适用于当前 Bean 的 Advisor:

    • 遍历得到的所有增强器列表
    • 对于每一个增强器,判断这个增强器里的pointcut是否与当前bean匹配。
    • 最后会得到一个筛选后的、只包含适用于当前 Bean 的 Advisor 的列表
    • 对筛选出的增强器列表进行排序
    • 创建代理对象,排序好的增强器列表会与这个代理对象关联起来

6、当调用代理对象的方法时,就会根据这个代理对象相关联的增强器列表构建出拦截器链,然后按顺序递归调用每一个拦截器,就能实现各个增强器的执行时机顺序。

二、@Transactional注解的底层原理

以上过程中,*查找基础设施Advisor:比如已经存在于容器中的 TransactionAdvisor。*对于这一步,你可能有疑惑,这个TransactionAdvisor增强器是啥时候存进容器里的?所以我们接下来分析@Transactional注解的底层原理。

1、@EnableTransactionManagement,依赖springboot自动装配原理。

项目中引入了 Spring Boot 的 依赖比如spring-boot-starter-web,这个依赖间接引入了 spring-boot-autoconfigure 这个JAR包,这个JAR包里的 META-INF下的文件中,定义了一长串自动配置类,其中就包括:

org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

当springboot启动后,会扫描这个文件里定义的每个类,当处理到TransactionAutoConfiguration这个类时,做了以下事:

@AutoConfiguration
@ConditionalOnClass({ PlatformTransactionManager.class })
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {// 这个配置只有在存在PlatformTransactionManager类型的Bean时才会生效// 而Spring Boot会自动根据您引入的依赖(如JDBC、JPA)自动创建一个事务管理器Bean@Configuration(proxyBeanMethods = false)@ConditionalOnBean(PlatformTransactionManager.class)@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)public static class EnableTransactionManagementConfiguration {// 关键在这里!@EnableTransactionManagementpublic static class ProxyTransactionManagementConfiguration {}}
}

ProxyTransactionManagementConfiguration 被解析的过程,实质上是Spring容器执行其内部 @Bean 方法,从而实例化和组装事务核心组件的过程。

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {// Bean 1: 事务属性源 - 负责解析@Transactional注解@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionAttributeSource transactionAttributeSource() {// 创建一个基于注解的事务属性源return new AnnotationTransactionAttributeSource();}// Bean 2: 事务拦截器 - 包含事务管理的核心逻辑(开启、提交、回滚)@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionInterceptor transactionInterceptor(TransactionAttributeSource tas) {TransactionInterceptor interceptor = new TransactionInterceptor();// 注入事务属性源,这样拦截器才知道如何解析注解interceptor.setTransactionAttributeSource(tas);// 注入事务管理器(来自父类),真正执行事务操作的组件if (this.txManager != null) {interceptor.setTransactionManager(this.txManager);}return interceptor;}// Bean 3: 事务增强器(Advisor) - 连接点(Pointcut)和通知(Advice)的组装体@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource,TransactionInterceptor transactionInterceptor) {BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();// 关键注入:设置事务属性源,它同时也充当了Pointcut的角色advisor.setTransactionAttributeSource(transactionAttributeSource);// 关键注入:设置通知(Advice),即我们的TransactionInterceptoradvisor.setAdvice(transactionInterceptor);// 设置Order,决定事务增强在代理链中的位置advisor.setOrder(this.enableTx.<Integer>getNumber("order"));return advisor;}
}
  1. 创建解析器:首先,执行 transactionAttributeSource() 方法,创建出 AnnotationTransactionAttributeSource。它的职责是解析 @Transactional 注解的属性。

  2. 创建执行器:接着,执行 transactionInterceptor() 方法。在这个过程中,Spring会将上一步创建的 TransactionAttributeSource 注入给新创建的 TransactionInterceptor。这个拦截器是事务的‘执行引擎’,包含了事务开启、提交、回滚的核心逻辑。

  3. 创建组装体:最后,执行 transactionAdvisor() 方法。Spring会将前两步创建好的 TransactionAttributeSourceTransactionInterceptor同时注入给新创建的 BeanFactoryTransactionAttributeSourceAdvisor

    这个Advisor是一个完整的组装体,既拥有了识别哪些方法需要事务的能力(来自AttributeSource),也拥有了执行事务操作的能力(来自Interceptor)。

http://www.xdnf.cn/news/19116.html

相关文章:

  • 12大主流本地文档管理系统功能与价格对比分析
  • 如何设置阿里云轻量应用服务器镜像?
  • v-model与v-bind区别
  • LG P5386 [Cnoi2019] 数字游戏 Solution
  • CesiumJS 介绍以及基础使用
  • 【完整源码+数据集+部署教程】硬币分类与识别系统源码和数据集:改进yolo11-SWC
  • GoogLeNet:深度学习中的“卷积网络变形金刚“
  • 从“安全诉讼”说起:奖励模型(Reward Model)是LLM对齐的总阀门(全视角分析)
  • 如何在实际应用中选择Blaze或Apache Gluten?
  • 【拍摄学习记录】06-构图、取景
  • 表复制某些字段的操作sql
  • LeetCode - 283. 移动零
  • 【lua】Lua 入门教程:从环境搭建到基础编程
  • 【面试场景题】dubbo可以使用自定义的序列化协议吗
  • 【ACP】2025-最新-疑难题解析-11
  • 虚拟内存和虚拟页面
  • 海量小文件问题综述和解决攻略(二)
  • Spring框架集成Kakfa的方式
  • 【完整源码+数据集+部署教程】工地建筑进度监测系统源码和数据集:改进yolo11-SDI
  • 【WebRTC】从入门到忘记
  • pytest使用allure测试报告
  • 迁移学习实战:医疗影像识别快速突破方案
  • 【查看css技巧】hover或者其他方式触发出来的样式如何查看
  • npm使用的环境变量及其用法
  • Socket编程核心API与结构解析
  • Java-面试八股文-Mysql篇
  • 【C语言】深入理解指针(1)
  • 什么是策略模式?策略模式能带来什么?——策略模式深度解析:从概念本质到Java实战的全维度指南
  • 20250829_编写10.1.11.213MySQL8.0异地备份传输脚本+在服务器上创建cron任务+测试成功
  • 保护海外服务器免受黑客攻击的方法