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

在这里插入图片描述

文章目录

    • 一、 解析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 {@Autowiredprivate OrderRepository orderRepository;@Transactionalpublic 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.rhkb.cn/news/336639.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[C#]使用C#部署yolov8的obb旋转框检测tensorrt模型

【测试通过环境】 win10 x64 vs2019 cuda11.7cudnn8.8.0 TensorRT-8.6.1.6 opencvsharp4.9.0 .NET Framework4.7.2 NVIDIA GeForce RTX 2070 Super 版本和上述环境版本不一样的需要重新编译TensorRtExtern.dll&#xff0c;TensorRtExtern源码地址&#xff1a;TensorRT-CShar…

最佳 Mac 数据恢复:恢复 Mac 上已删除的文件

尝试过许多 Mac 数据恢复工具&#xff0c;但发现没有一款能达到宣传的效果&#xff1f;我们重点介绍最好的 Mac 数据恢复软件 没有 Mac 用户愿意担心数据丢失&#xff0c;但您永远不知道什么时候会发生这种情况。无论是意外删除 Mac 上的重要文件、不小心弄湿了 Mac、感染病毒…

【MySQL用户管理】

文章目录 1.用户信息2.创建用户3.删除用户4.修改用户密码5.给用户设置权限展示zhangsan用户的权限 6.回收权限 1.用户信息 host&#xff1a; 表示这个用户可以从哪个主机登陆&#xff0c;如果是localhost&#xff0c;表示只能从本机登陆 user&#xff1a; 用户名 authenticatio…

【记忆化搜索 】2312. 卖木头块

本文涉及知识点 记忆化搜索 LeetCode2312. 卖木头块 给你两个整数 m 和 n &#xff0c;分别表示一块矩形木块的高和宽。同时给你一个二维整数数组 prices &#xff0c;其中 prices[i] [hi, wi, pricei] 表示你可以以 pricei 元的价格卖一块高为 hi 宽为 wi 的矩形木块。 每…

【刷题(12)】图论

一、图论问题基础 在 LeetCode 中&#xff0c;「岛屿问题」是一个系列系列问题&#xff0c;比如&#xff1a; 岛屿数量 &#xff08;Easy&#xff09;岛屿的周长 &#xff08;Easy&#xff09;岛屿的最大面积 &#xff08;Medium&#xff09;最大人工岛 &#xff08;Hard&…

数据库设计:实体关系图

一个良好的设计对于数据库系统至关重要&#xff0c;它可以减少数据冗余&#xff0c;确保数据的一致性和完整性&#xff0c;同时使得数据库易于维护和扩展。 实体关系图&#xff08;Entity-Relationship Diagram、ERD&#xff09;是一种用于数据库设计的结构图&#xff0c;它描…

使用LLaMA-Factory微调大模型

使用LLaMA-Factory微调大模型 github 地址 https://github.com/hiyouga/LLaMA-Factory 搭建环境 git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factory在 LLaMA-Factory 路径下 创建虚拟环境 conda create -p ./venv python3.10激活环境 c…

arduino + ov7670实现拍照

前言 用一个几块钱的 ov7670 摄像头加 arduino 来进行拍照实现。本文只是实现了模块的拍照功能。没有进行深入的研究&#xff0c;拍出来的视频不是流畅的&#xff0c;大概间隔6s会刷新一次。 图片预览 视频预览 arduino和ov7670实现拍照-哔哩哔哩 材料准备 材料数量价格(r…

北京大学第一医院与智源研究院共同发布基于可信执行环境的AI医学影像挑战赛

肾动脉狭窄是导致继发性高血压及肾功能不全的常见原因&#xff0c;而目前针对肾动脉狭窄功能学的评估尚处于探索阶段。数据保护和可信计算环境是目前人工智能技术应用于临床研究的一大瓶颈。北京大学第一医院与北京智源人工智能研究院心脏AI 联合研究中心特发布基于可信执行环境…

信号与槽函数的魔法:QT 5编程中的核心机制

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、信号与槽函数的基本概念 二、信号与槽函数的实现原理 三、信号与槽函数的代码实例 四…

npm镜像源管理、nvm安装多版本node异常处理

查看当前使用的镜像源 npm config get registry --locationglobal 设置使用官方源 npm config set registry https://registry.npmjs.org/ --locationglobal 设置淘宝镜像源 npm config set registry https://registry.npm.taobao.org/ --locationglobal 需要更改淘宝镜像源地址…

03.k8s常用的资源

3.k8s常用的资源 3.1 创建pod资源 k8s yaml的主要组成 apiVersion: v1 api版本 kind: pod 资源类型 metadata: 属性 spec: 详细上传nginx镜像文件&#xff0c;并且上传私有仓库里面 k8s_pod.yaml apiVersion: v1 kind: Pod metadata:name: nginxlabels:app: we…

自制数据#国家2000投影带划分范围shp(高斯克吕格 3°/6°分带)

国家2000投影分带范围&#xff08;3&#xff09; https://www.123pan.com/s/lqEljv-xvCHA.html 国家2000投影分带范围&#xff08;6&#xff09; https://www.123pan.com/s/lqEljv-xvCHA.html 声明&#xff1a;转载此文不为商业用途。文字和图片版权归原作者所有&#xff0c;…

【Python编程实践2/3】Python图像处理模块(上)

目录 引言 目标 安装模块 Windows系统 macOS系统 路径 Windows路径 ​编辑macOS路径 windows路径报错 windows路径前的r 示例代码 windows快速查看路径 macOS快速查看路径 打开图片 展示图片 下节预告 总结 引言 欢迎各位大佬垂阅本篇Python实践博客&a…

vue-Dialog 自定义title样式

展示结果 vue代码 <el-dialog :title"title" :visible.sync"classifyOpen" width"500px" :showClose"false" class"aboutDialog"> <el-form :model"classifyForm" :rules"classifyRules">…

【赠书第26期】AI绘画教程:Midjourney使用方法与技巧从入门到精通

文章目录 前言 1 Midjourney入门指南 1.1 注册与登录 1.2 界面熟悉 1.3 基础操作 2 Midjourney进阶技巧 2.1 描述词优化 2.2 参数调整 2.3 迭代生成 3 Midjourney高级应用 3.1 创意启发 3.2 团队协作 3.3 商业应用 4 总结与展望 5 推荐图书 6 粉丝福利 前言 在…

自动控制:控制系统的稳定性

自动控制&#xff1a;控制系统的稳定性 在自动控制领域&#xff0c;控制系统的稳定性是一个至关重要的问题。稳定性决定了系统在受到扰动后是否能够恢复到平衡状态。本文将介绍控制系统稳定性的基本概念、如何利用特征值分析稳定性&#xff0c;并通过具体示例和Python代码展示…

【香橙派 AIpro】新手保姆级开箱教程:Linux镜像+vscode远程连接

香橙派 AIpro 开发板 AI 应用部署测评 写在最前面一、开发板概述官方资料试用印象适用场景 二、详细开发前准备步骤1. 环境准备2. 环境搭建3. vscode安装ssh插件4. 香橙派 AIpro 添加连接配置5. 连接香橙派 AIpro6. SSH配置 二、详细开发步骤1. 登录 juypter lab2. 样例运行3. …

基于51单片机的温度+烟雾报警系统设计

一.硬件方案 本设计采用51单片机为核心控制器&#xff0c;利用气体传感器MQ-2、ADC0832模数转换器、DS18B20温度传感器等实现基本功能。通过这些传感器和芯片&#xff0c;当环境中可燃气体浓度或温度等发生变化时系统会发出相应的灯光报警信号和声音报警信号&#xff0c;以此来…

【C语言回顾】预处理

前言1. 简单概要2. 预处理命令讲解结语 上期回顾: 【C语言回顾】编译和链接 个人主页&#xff1a;C_GUIQU 归属专栏&#xff1a;【C语言学习】 前言 各位小伙伴大家好&#xff01;上期小编给大家讲解了C语言中的编译和链接&#xff0c;接下来我们讲解一下预处理&#xff01; …