Spring 源码:深度解析AOP源码配置解析

news2024/11/17 1:43:40

在这里插入图片描述

文章目录

    • 一、 解析AOP配置的入口
      • 1.1 从XML配置到AOP Namespace的解析流程
      • 1.2 分析注解驱动的AOP配置解析流程
    • 二、AOP配置解析的核心流程
      • 2.1 ConfigBeanDefinitionParser 类
      • 2.2 parse()
      • 2.3 parseAdvisor()
      • 2.4 parseAspect()
      • 2.5 parsePointcut()
      • 2.6 createAdvisorBeanDefinition()
      • 2.7 createPointcutDefinition()
    • 三、设计模式
      • 3.1 JDK 动态代理
      • 3.2 CGLIB 代理
      • 3.3 AOP 面向切面
    • 四、实际与应用

一、 解析AOP配置的入口

1.1 从XML配置到AOP Namespace的解析流程

流程解析

  1. 加载配置文件:Spring 应用启动时加载 XML 配置文件。
  2. 解析 XML 配置
    • Spring 解析器会识别 AOP 相关的 XML 元素, 如 <aop:config><aop:aspect><aop:pointcut><aop:before> 等 。
    • 对于使用 AOP 命名空间的配置,Spring 会根据命名空间中定义的 schema 头文件来解析配置。
  3. 创建切面和通知
    • Spring 解析到 <aop:aspect> 元素时,会创建对应的切面,并指定切面的 ID 和引用的 bean
    • 解析<aop:before><aop:after> 等元素时,会创建对应的通知,并指定通知要执行的方法。
  4. 解析切点
    • 当解析到 <aop:pointcut> 元素时,Spring 会创建一个切点,并指定切点的 ID 和表达式。
  5. 应用切面和通知
    • Spring 将切面、切点和通知组合在一起,根据配置中的切点表达式找到目标方法。
    • 然后,Spring 根据配置的通知类型(如前置通知、后置通知等),将通知织入到目标方法的执行流程中。
  6. 创建代理对象
    • 如果目标类被代理,Spring 将根据配置创建代理对象。
    • 对于基于接口的代理,Spring 使用 JDK 动态代理。
    • 对于基于类的代理,Spring 使用 CGLIB 动态代理。
  7. 运行时织入
    • 当应用程序运行时调用目标方法时,代理对象会按照配置织入相应的通知,实现切面功能。
  8. 执行目标方法
    • 最后,Spring 框架会执行被代理的目标方法,并在执行过程中触发配置的通知。

1.2 分析注解驱动的AOP配置解析流程

解析流程

  1. 扫描组件
    • Spring 应用启动时,会扫描指定的包路径下的组件,并解析其中的注解。
  2. 解析切面
    • Spring 容器会检测到被 @Aspect 注解标记的类,并将其识别为切面类。
    • 在切面类中,Spring 解析带有 @Before@After@Around 等注解的方法,这些注解表示切面的通知类型。
  3. 识别切点
    • 切面类中的方法可能带有 @Pointcut 注解,用于定义切点表达式,Spring 会解析这些表达式并创建切点。
  4. 应用通知
    • Spring 解析切面类中带有 @Before@After@Around 等注解的方法,并将其作为通知,与对应的切点关联。
  5. 创建代理对象
    • 对于被代理的目标类,Spring 根据配置情况选择使用 JDK 动态代理还是 CGLIB 动态代理。
    • 如果目标类实现了接口且配置了基于接口的代理,则使用 JDK 动态代理;否则,使用 CGLIB 动态代理。
  6. 运行时织入
    • 当应用程序调用被代理的目标方法时,Spring 框架会根据切面和通知的配置,在方法执行前后织入相应的通知。
  7. 执行目标方法
    • 最终,Spring 框架会执行被代理的目标方法,并在执行过程中触发配置的通知,完成 AOP 的功能。

二、AOP配置解析的核心流程

2.1 ConfigBeanDefinitionParser 类

ConfigBeanDefinitionParser 类是 AOP 配置的 Bean 定义解析器。负责解析 <aop:config> 标签中的配置信息,并将解析结果应用到 Spring 的 Bean 定义中。

主要责任

  1. 解析 AOP 配置信息:解析<aop:config> 标签及其子标签中的配置信息,包括切面定义、通知类型、切点表达式等。
  2. 创建切面相关的 BeanDefinition:根据解析的配置信息,创建切面相关的 BeanDefinition 对象,包括切面、通知等。
  3. 注册 BeanDefinition:将解析得到的 BeanDefinition 注册到 Spring 的 BeanFactory 中,使得这些切面相关的组件可以被容器管理。
  4. 处理切面相关的后处理逻辑:在注册切面相关的 BeanDefinition 之前或之后,可能需要进行一些额外的后处理逻辑,如检查和修正配置、添加其他配置等。

2.2 parse()

根据 <aop:config> 元素及其子元素的配置信息,进行相应的解析和处理,最终将 AOP 相关的配置信息转换为 Spring 容器内部的数据结构。

在这里插入图片描述

2.3 parseAdvisor()

解析<advisor>元素及其子元素的配置信息,并根据解析结果注册相应的 BeanDefinition 到 Spring 容器中。

在这里插入图片描述

2.4 parseAspect()

负责解析 <aspect> 元素及其子元素的配置信息,并根据解析结果注册相应的 BeanDefinition 到 Spring 容器中。

在这里插入图片描述

2.5 parsePointcut()

解析切点元素,获取idexpression属性的值,并根据这些值创建和注册切点定义对象。

在这里插入图片描述

2.6 createAdvisorBeanDefinition()

根据传入的参数创建一个切面通知 Bean 定义对象,并设置相应的属性和构造器参数。

在这里插入图片描述

2.7 createPointcutDefinition()

创建一个切点定义的 Bean,并设置其作用域、合成标记和表达式属性值,然后返回该 Bean 定义对象。

在这里插入图片描述

三、设计模式

3.1 JDK 动态代理

  1. 代理模式:JDK 动态代理是典型的代理模式的应用。
    • 在代理模式中,代理对象充当了客户端和真实对象之间的中介,控制对真实对象的访问。
    • JDK 动态代理中的代理对象就扮演了这样的角色,它通过实现目标对象相同的接口,并持有目标对象的引用,在调用方法时将请求转发给目标对象。
    • 代理模式的使用可以实现对目标对象的访问控制、延迟加载等功能。
  2. 装饰器模式:在 JDK 动态代理中,InvocationHandler 接口扮演了类似于装饰器模式中的装饰器的角色。
    • InvocationHandler 接口包含了对方法的调用处理逻辑,类似于装饰器模式中的装饰器对对象进行额外的包装和处理。
    • 通过 InvocationHandler 的实现类,可以在目标对象的方法调用前后加入额外的逻辑,从而实现类似于装饰器模式的功能。
  3. 工厂模式:JDK 动态代理中的 Proxy 类通过 newProxyInstance 方法动态创建代理对象。
    • newProxyInstance 方法可以看作是一个工厂方法,根据传入的类加载器、接口数组和 InvocationHandler 对象动态产生代理对象。
  4. 反射模式:JDK 动态代理的实现基于 Java 的反射机制。
    • 通过反射机制可以在运行时获取并操作类、对象、接口等信息。
    • 代理对象在接收到方法调用时,利用反射机制将调用转发给 InvocationHandler 中的 invoke 方法进行处理,从而实现代理的功能。

3.2 CGLIB 代理

  1. 委托模式:CGLIB代理通过生成目标类的子类来实现代理。
    • 在子类中重写目标方法并调用代理逻辑。
    • 这种方式类似于委托模式,即将目标对象的功能委托给代理对象来实现。
  2. 模板方法模式:CGLIB生成的代理类通常使用了模板方法模式。
    • 在生成的子类中定义模板方法,并在模板方法中调用用户定义的回调方法(如代理逻辑)。
    • 这样设计使得用户能够通过继承代理类并重写回调方法来定义自己的代理逻辑。
  3. 工厂模式:CGLIB代理通常涉及到代理类的创建过程,可看作是工厂模式的应用。
    • CGLIB通过字节码生成技术在运行时动态生成代理类,为客户端提供了一种动态创建代理对象的方式,符合工厂模式的特点。
  4. 策略模式:CGLIB代理允许用户通过定义回调方法来实现代理逻辑,这样的设计类似于策略模式的应用。
    • 用户可以根据需要定义不同的代理策略(即不同的回调方法),并将其传递给CGLIB来生成相应的代理类。
  5. 反射模式:CGLIB的实现基于对类的字节码进行操作,这样的设计类似于反射模式的应用。
    • CGLIB使用了反射来生成代理类的字节码,并在运行时加载和处理这些字节码,从而实现代理功能。

3.3 AOP 面向切面

  1. 代理模式:AOP 中的代理对象充当了目标对象和横切逻辑之间的中介,控制对目标对象方法的访问。
    • 通过代理模式,AOP实现了横切逻辑的注入,并在目标方法执行前后执行额外的逻辑,如日志记录、性能监控等。
  2. 装饰器模式:AOP 中的横切逻辑类似于装饰器模式中的装饰器。
    • 在目标方法的执行前后加入额外的逻辑。
    • AOP框架在运行时动态地将这些横切逻辑织入到目标对象的方法调用中,类似于装饰器模式中的装饰器对对象进行包装和处理。
  3. 观察者模式:AOP中的切面可以理解为观察者,观察目标对象方法的执行,并在特定的切点上执行相应的逻辑。
    • 切面可以订阅特定的切点,当这些切点被触发时,切面就会执行相应的逻辑,类似于观察者模式中的观察者对目标对象的变化做出反应。
  4. 工厂模式:AOP框架通常使用了工厂模式来创建代理对象。
    • 通过配置文件或注解等方式定义切面和切点,AOP框架会根据这些定义动态地创建代理对象,并将横切逻辑织入到目标对象的方法调用中,从而实现面向切面编程的功能。
  5. 模板模式:AOP框架中的代理对象通常使用了模板模式。
    • AOP框架提供了一种模板化的方式来定义横切逻辑,并在执行目标方法前后调用相应的模板方法,这样的设计使得用户能够通过继承并重写模板方法来定义自己的横切逻辑。

四、实际与应用

如何在实际项目中应用 Spring AOP 实现事务管理

假设有一个 简单的订单管理系统,包含订单服务和相关的实体类。希望在创建订单的过程中实现事务管理,即要么全部成功,要么全部失败。

  1. 添加依赖。
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 其他依赖 -->
  1. 定义订单实体类 Order 。
/**
 * @Entity: 这个注解表明这是一个 JPA 实体类
 * 
 */
@Entity
public class Order {
    /**
     * @Id: 表示该字段是实体类的主键
     * @GeneratedValue: 指定了主键的生成策略 -> GenerationType.IDENTITY:主键值会自动增加
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String orderNumber;

    private double amount;

    // Getters and setters
}
  1. 定义订单服务类 OrderService,并添加创建订单的方法。
/**
 * 在方法上添加 @Transactional 注解,Spring AOP 可以在方法执行前后自动管理事务的开启、提交和回滚
 */
@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    @Transactional
    public void createOrder(String orderNumber, double amount) {
        Order order = new Order();
        order.setOrderNumber(orderNumber);
        order.setAmount(amount);
        orderRepository.save(order);
    }
}
  1. 配置事务管理:在 Spring Boot 主类上添加 @EnableTransactionManagement 注解,启用事务管理。
@SpringBootApplication
@EnableTransactionManagement
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

攀登顶峰,这种奋斗的本身就足以充实人的心

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1717028.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CentOS 7基础操作02_优化Linux操作系统中的服务

1、实验环境 公司在文件服务器中新安装了CentOS系统.由于默认启动的服务程序较多&#xff0c;系统运行缓慢。现需要对系绞服务进行适当优化&#xff0c;减少一些不必要的自启动服务.并设置系统在开机后直接进入字符模式。 2、需求描述 根据实际使用需求对CentOS 7操作系统中的…

C++第二十二弹---vector深度剖析及模拟实现(下)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1、容量操作 2、内容修改操作 3、打印函数 4、迭代器失效 4.1、什么是迭代器失效 4.2、哪些操作会引起迭代器失效 总结 1、容量操作 size()…

【Docker】宝塔创建Docker容器配置nginx

前言 本篇是我入门docker的第一篇&#xff0c;由于docker具有很好的移植性&#xff0c;易于安装&#xff0c;开箱即用&#xff1b;签约的公司项目开发需要我进行学习&#xff0c;否则money减半&#xff0c;5555~ 百度找了一圈&#xff0c;只有关于docker怎么装宝塔服务器的却没…

从Socket到WebSocket

前言 不知道大家在学习网络编程的时候都是怎样的一种方式&#xff0c;我谨以此文章来记录我自己从头开始学习C网络编程时的经历&#xff0c;中间有许多我自己的一些想法和思考。当然作为一个刚开始学习的新手来说&#xff0c;有些内容也许不那么正确&#xff0c;只是代表了我在…

【Qt知识】Qt Creator快捷键

以下是Qt Creator中的一些常用快捷键列表&#xff08;持续更新&#xff09;&#xff1a; 基本编辑 多行注释/取消多行注释: Ctrl /编译工程: Ctrl B运行工程: Ctrl R整行上移/下移: Ctrl Shift ↑/↓查找: Ctrl F函数声明和定义切换: F2向下查找: F3头文件和源文件切换:…

SAPUI5基础知识3 - 引导过程(Bootstrap)

1. 背景 在上一篇博客中&#xff0c;我们已经建立出了第一个SAPUI5项目&#xff0c;接下来&#xff0c;我们将为这个项目添加引导过程。 在动手练习之前&#xff0c;让我们先解释一下什么引导过程。 1.1 什么是引导过程&#xff1f; 在计算机科学中&#xff0c;引导过程也称…

苹果如何设置自动循环壁纸?这几种不同的方法你要学会

在使用手机的时候&#xff0c;我们可能会经常更换手机壁纸&#xff0c;遇见好看或者有意义的图片时就想将其设置为壁纸&#xff0c;你知道 iPhone 手机可以设置自动循环壁纸吗&#xff1f;如果你不了解下面就带你一起看看 iPhone 手机如何设置壁纸自动循环。 壁纸程序设置 想…

GIS之arcgis系列06:线划图缓冲区分析

缓冲区工具将在输入要素周围指定距离内创建缓冲区面。 缓冲区例程将遍历输入要素的每个折点并创建缓冲区偏移。 通过这些偏移创建输出缓冲区要素 原理&#xff1a; 01.打开文件 02.确定单位&#xff0c;在文件属性里。 03.工具箱-->分析工具-->邻域分析-->缓冲区。 …

藏汉翻译通小程序——你口袋里的藏语翻译助手!支持高精度藏文OCR文字识别提取,安卓iPhone手机都能用的藏汉翻译小助手!

想要快速学习藏语或者与藏族朋友无障碍沟通吗&#xff1f;藏汉翻译通小程序绝对是你的不二之选&#xff01; 这款小程序不仅界面简洁、操作便捷&#xff0c;更重要的是它集合了多种实用功能于一身。 双语翻译&#xff1a;无论你是藏族还是汉族&#xff0c;只需输入文字&#…

C#中的实体属性详解与示例

文章目录 实体属性的定义实体属性的访问实体属性的示例总结 在C#中&#xff0c;实体属性是面向对象编程的重要组成部分。实体属性允许我们定义对象的特征和行为&#xff0c;并提供了一种方式来访问和管理这些特征。通过实体属性&#xff0c;我们可以封装对象的状态&#xff0c;…

【Linux】Linux基本指令3

目录 1.date指令 2.cal指令 3.find指令&#xff1a;&#xff08;灰常重要&#xff09; -name 4.grep指令——行文本过滤工具 5.zip/unzip指令&#xff1a; 6.tar指令&#xff08;重要&#xff09;&#xff1a;打包/解包&#xff0c;不打开它&#xff0c;直接看内容 7.bc…

OSPF学习笔记(状态机)

1、邻居关系 OSPF设备启动后&#xff0c;会通过OSPF接口向外发送Hello报文&#xff0c;收到Hello报文的OSPF设备会检查报文中所定义的参数&#xff0c;如果双方一致就会形成邻居关系&#xff0c;两端设备互为邻居 2、邻接关系 形成邻居关系后&#xff0c;如果两端设备成功交…

Spring boot集成通义千问大模型

Spring boot集成通义千问大模型 背景 我在用idea进行java开发时发现了通义灵码这款免费的智能代码补全插件&#xff0c;用了一段时间了&#xff0c;感觉很不错。就想着在自己的项目中也能集成通义千问大模型实现智能回答&#xff0c;毕竟对接openai需要解决网络问题&#xff…

[学习笔记]知乎文章-PyTorch的Transformer

参考资料&#xff1a; PyTorch的Transformer register_buffer的作用是&#xff1a;登记成员变量&#xff0c;它会自动成为模型中的参数&#xff0c;随着模型移动&#xff08;gpu/cpu&#xff09;而移动&#xff0c;但是不会随着梯度进行更新。 参考资料&#xff1a;【Torch API…

【云原生】kubernetes中pod的生命周期、探测钩子的实战应用案例解析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

向量数据库引领 AI 创新——Zilliz 亮相 2024 亚马逊云科技中国峰会

2024年5月29日&#xff0c;亚马逊云科技中国峰会在上海召开&#xff0c;此次峰会聚集了来自全球各地的科技领袖、行业专家和创新企业&#xff0c;探讨云计算、大数据、人工智能等前沿技术的发展趋势和应用场景。作为领先的向量数据库技术公司&#xff0c;Zilliz 在本次峰会上展…

Pont在小程序开发的使用

Pont是一个很好的前后端桥&#xff0c;但是有个问题。默认产生的代码&#xff0c;无法支持微信小程序开发。根本原因是因为使用了window给全局的对象注入了API和refs属性&#xff0c;由于小程序没有window属性&#xff0c;当然就无法使用了&#xff0c;解决办法也比较简单。只需…

轻松入门:HTML网页制作指南 进阶篇

一.表格标签 1.1表格的主要作用 表格不是用来布局页面的,而是用来展示数据的。 1.2基本语法 <table><tr><td>单元格内的文字</td>...</tr>...</table>说明&#xff1a; 1.<table> </table> 是用于定义表格的标签。 2.<t…

Iphone自动化指令每隔固定天数打开闹钟关闭闹钟(一)

注意&#xff1a;因为是第一次用iphone的快捷指令&#xff0c;不是很明白&#xff0c;所以之后多次运行发现有bug&#xff0c;所以快捷指令部分在下一章重新写&#xff0c;我用两个日期测试了&#xff0c;没问题&#xff0c;这一章可以当做熟悉快捷指令的一些操作用&#xff0c…

【协议开发系列】梳理关于TCP和UDP两种协议的区别和使用场景

起源 前二天项目上在核对外部对接服务的五元组列表的时候&#xff0c;有一位客户提问对于同样的服务同时支持tcp和udp二种方式&#xff0c;有什么优点和缺点&#xff0c;应该如何选择&#xff1f;这个问题突然让我愣了一下&#xff0c;确实好久没有“温故”了&#xff0c;相关…