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

spring aop源码解析

spring知识回顾

        spring的两个重要功能:IOC、AOP,在ioc容器的初始化过程中,会触发2种处理器的调用,

前置处理器(BeanFactoryPostProcessor)后置处理器(BeanPostProcessor)。

        前置处理器的调用时机是在容器基本创建完成时,可以往容器中添加各种的bean

        后置处理器的调用时机是在bean的初始化和实例化时调用,aop的功能就是基于该特性实现的

aop重要的类介绍

        org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator spring的aop实现的入口类

        org.springframework.aop.Pointcut  spring的aop的顶层切面接口

        org.aopalliance.aop.Advice   spring的aop的顶层通知接口

        org.springframework.aop.Advisor  aop的顶层接口,从语义上包含了:pointcut和advice

   aop的使用     

        如果在实际的工作中,需要做aop操作,可以基于spring的aop返回实现也可以基于AspectJ操作实现,前者是在运行时动态代理,后置是在编译阶段完成aop,这里只讨论spring的aop使用

       切面:

           spring提供了多种切面:静态切面、动态切面、注解切面、正则表达式切面等

      通知advice:

         spring提供了多种通知:BeforeAdvice、AfterAdvice

   动态方法判断aop使用:

        1  切面类继承 org.springframework.aop.support.DynamicMethodMatcherPointcut

        org.springframework.aop.support.DynamicMethodMatcherPointcut#getClassFilter方法根据业务条件重新判断

        org.springframework.aop.MethodMatcher#matches(java.lang.reflect.Method, java.lang.Class<?>, java.lang.Object...)方法在运行时根据传入的方法参数动态判断

        2 通知类实现org.aopalliance.intercept.MethodInterceptor

        org.aopalliance.intercept.MethodInterceptor#invoke方法根据实际情况编写执行代码

       3 组装org.springframework.aop.support.DefaultPointcutAdvisor

        将切面和通知类织入到Advisor中,同时把Advisor做为bean放入到spring的ioc容器即可

源码解析

        spring的aop的入口是在spring bean创建过程中由后置处理器完成的,入口类是:

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator,查看类的UML图如下:

由图可知:该类是一个BeanPostProcessor的子类,在bean被初始化时,会调用该类的两个方法:

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInitialization

和org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

aop的入口就是在bean初始化后的调用:

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary方法如下图所示:

spring的aop涉及的精髓就在这2段代码中

 获取符合的Advisor。根据代码逻辑一路调试:org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors

 其中第一步是获取所有的Advisor类,在第二步的时候通过beanClass筛选出符合条件的Advisor

最终的筛选逻辑在:org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)

  在上面的简单使用的第一步中,有继承成DynamicMethodMatcherPointcut,DyNamicMethodMatcherPointcut同时也是MethodMatcher的实现,在上图1处是对类判断是否满足条件,DynamicMethodMatcherPointcut此处对所有的类都会返回true,可以根据业务情况选择性的返回,提升性能

在2处获取的也是DynamicMethodMatcherPointcut本身,也是对所有的方法返回true

至此,通过DynamicMethodMatcherPointcut在bean初始化时寻找到合适的Advisor,下一步就是创建代理org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy

在1处传入的就是由上一个步骤查询到的合适的Advisor列表,2处做转换,3处就是正在的创建代理的逻辑,跟随代码一路调试。最终Aop的代理创建委托给了org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy

会根据bean的类型判断是采用Jdk动态代理还是cglib动态代理完成。后面bean的执行逻辑就是代理的相关方法逻辑了。

至此,Aop的创建过程梳理完成

大家最关心的其实是动态代理的执行逻辑。这里暂时先以JDK的动态代理为列分析源码流程

后续的代码分析如下:

org.springframework.aop.framework.JdkDynamicAopProxy的类UML图如下:

真正的执行逻辑应该是org.springframework.aop.framework.JdkDynamicAopProxy#invoke方法

前面的方法是做一些固定方法判断,包括:equal、hashcode等,核心方法如截图所示

在1处获取调用该方法的拦截链,最终的实现委托给了:org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice

在代码1处,获取该方法对应类的Advisor列表,在2处通过org.springframework.aop.support.DynamicMethodMatcher#matches方法判断,此处恒为true,在3处就是区别DynamicMethodmatcherPointcut和StaticMethodmatcherPointcut的地方,动态的此处为true,而StaticMethodMatcherPointcut为false。最终返回的是通知类Advice(MethodInterceptor是Advice的子类)

回到org.springframework.aop.framework.JdkDynamicAopProxy#invoke的第二步,当通知不为空时,通过构造了一个ReflectiveMethodInvocation对象,再调用org.springframework.aop.framework.ReflectiveMethodInvocation#proceed方法返回结果

跟踪代码到org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

在构造器中,传入了拦截器链,在真正实行时,通过链路调用完成

至此Aop的创建实现和执行逻辑已经梳理清楚,总结如下:

代理创建逻辑:

  1 AbstractAutoProxyCreator是一个BeanPostProcessor,在bean初始化时会触发

postProcessAfterInitialization方法的调用

2  org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary方法通过bean的类类型寻找到对应的通知类Advisor

3 代理的创建委托给了org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy方法实现,通过判断bean的条件采用JDK或者cglib的动态代理方式实现

JDK代理实现逻辑如下:

当执行方法时,通过代理,

1 调org.springframework.aop.framework.JdkDynamicAopProxy#invoke方法。

2 该方法通过获取调用方法对应的通知信息,然后构建一个ReflectiveMethodInvocation实例,最终调用委托给了ReflectiveMethodInvocation#proceed方法

3 ReflectiveMethodInvocation#proceed方法调用通知链的所有拦截器方法

以上就是Aop的创建和代理执行全逻辑

相关文章:

spring aop源码解析

spring知识回顾 spring的两个重要功能&#xff1a;IOC、AOP&#xff0c;在ioc容器的初始化过程中&#xff0c;会触发2种处理器的调用&#xff0c; 前置处理器(BeanFactoryPostProcessor)后置处理器(BeanPostProcessor)。 前置处理器的调用时机是在容器基本创建完成时&#xff…...

使用Unity的Input.GetAxis(““)控制物体移动、旋转

使用Unity的Input.GetAxis("")控制物体移动、旋转 Input.GetAxis("") 是 Unity 引擎中的一个方法&#xff0c;用于获取游戏玩家在键盘或游戏手柄上输入的某个轴&#xff08;Axis&#xff09;的值。这里的 "" 是一个字符串参数&#xff0c;表示要…...

【CSS】画个三角形或圆形或环

首先通过调整边框&#xff0c;我们可以发现一些端倪 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><style>.box{width: 150px;height:150px;border: 50px solid black;}</style&g…...

AI项目六:基于YOLOV5的CPU版本部署openvino

若该文为原创文章&#xff0c;转载请注明原文出处。 一、CPU版本DEMO测试 1、创建一个新的虚拟环境 conda create -n course_torch_openvino python3.8 2、激活环境 conda activate course_torch_openvino 3、安装pytorch cpu版本 pip install torch torchvision torchau…...

记录YDLidar驱动包交叉编译时出现的一点问题

由于一不小心把交叉编译的系统根目录破坏了&#xff0c;所以一股脑将交叉编译系统根目录全删了重新安装&#xff0c;安装后&#xff0c;交叉编译发现ydlidar的ros包驱动出现了库无法链接的错误(刚刚还是好好的)&#xff0c;但是又想不起来之前是怎么解决的了&#xff0c;所以还…...

嵌入式学习笔记(32)S5PV210的向量中断控制器

6.6.1异常处理的2个阶段 可以将异常处理分为2个阶段来理解。第一个阶段是异常向量表跳转&#xff1b;第二个阶段是进入了真正的异常处理程序irq_handler之后的部分。 6.6.2回顾&#xff1a;中断处理的第一个阶段&#xff08;异常向量表跳转阶段&#xff09;处理 &#xff08;…...

linux下安装qt、qt触摸屏校准tslib

linux下安装qt 在 Linux 系统下安装 Qt&#xff0c;可以通过以下步骤进行操作&#xff1a;1. 下载 Qt 安装包&#xff1a;首先&#xff0c;你需要从 Qt 官方网站&#xff08;https://www.qt.io/&#xff09;下载适用于 Linux 的 Qt 安装包。选择与你的系统和需求相匹配的版本&…...

C++之unordered_map,unordered_set模拟实现

unordered_map&#xff0c;unordered_set模拟实现 哈希表源代码哈希表模板参数的控制仿函数增加正向迭代器实现*运算符重载->运算符重载运算符重载! 和 运算符重载begin()与end()实现 unordered_set实现unordered_map实现map/set 与 unordered_map/unordered_set对比哈希表…...

React Router,常用API有哪些?

react-router React Router是一个用于构建单页面应用程序&#xff08;SPA&#xff09;的库&#xff0c;它是用于管理React应用中页面导航和路由的工具。SPA是一种Web应用程序类型&#xff0c;它在加载初始页面后&#xff0c;通过JavaScript来动态加载并更新页面内容&#xff0…...

JVM类加载和双亲委派机制

当我们用java命令运行某个类的main函数启动程序时&#xff0c;首先需要通过类加载器把类加载到JVM&#xff0c;本文主要说明类加载机制和其具体实现双亲委派模式。 一、类加载机制 类加载过程&#xff1a; 类加载的过程是将类的字节码加载到内存中的过程&#xff0c;主要包括…...

P-MVSNet ICCV-2019 学习笔记总结 译文 深度学习三维重建

文章目录 5 P-MVSNet ICCV-20195.0 主要特点5.1 文章概述5.2 研究方法5.2.1 特征提取5.2.2 学习局域匹配置信5.2.3 深度图预测5.2.4 Loss方程MVSNet系列最新顶刊 对比总结5 P-MVSNet ICCV-2019 深度学习三维重建 P-MVSNet-ICCV-2019(原文、译文、批注) 下载 5.0 主要特点 …...

vueshowpdf 移动端pdf文件预览

1、安装 npm install vueshowpdf -S2、参数 属性说明类型默认值v-model是否显示pdf--pdfurlpdf的文件地址String- scale 默认放大倍数 Number1.2 minscale 最小放大倍数 Number0.8 maxscale 最大放大倍数 Number2 3、事件 名称说明回调参数closepdf pdf关闭事件-pdferr文…...

C#根据excel文件中的表头创建数据库表

C#根据excel文件中的表头创建数据库表 private void button1_Click(object sender, EventArgs e){string tableName tableNameTextBox.Text;string connectionString "";using (OpenFileDialog openFileDialog new OpenFileDialog()){openFileDialog.Filter &quo…...

js通过xpath定位元素并且操作元素以下拉框select为例

js也可以使用xpath定位元素&#xff0c;现在实例讲解。 页面上有一个下拉框&#xff0c;里面内容有三个&#xff0c;用F12看一下 一、使用xpath定位这个下拉框select eldocument.evaluate(//select[name"shoppingPreference"], document).iterateNext()二、为下拉框…...

数据类型

目录 1.数值类型 整数类型 int 小数类型 double 2.字符类型 固定长度字符串 char 可变长度字符串 varchar 3.日期时间类型 日期类型&#xff1a;date 日期时间类型&#xff1a;datetime MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article…...

vue 模板应用

一&#xff0c;模板应用也就是对DOM的操作 二&#xff0c;如何使用 通过标签里面添加ref 和vue中使用 this.$refs.ref的名字.操作 进行使用 <template><h3>模板引用</h3><div ref"cont" class"cont">{{ content }}</div>&…...

Golang教程与Gin教程合集,入门到实战

GolangGin框架GormRbac微服务仿小米商城项目实战视频教程Docker Swarm K8s云原生分布式部署 介绍&#xff1a; Go即Golang&#xff0c;是Google公司2009年11月正式对外公开的一门编程语言&#xff0c;它不仅拥有静态编译语言的安全和高性能&#xff0c;而 且又达到了动态语言开…...

国家网络安全周 | 天空卫士荣获“2023网络安全优秀创新成果大赛优胜奖”

9月11日上午&#xff0c;四川省2023年国家网络安全宣传周在泸州开幕。在开幕式上&#xff0c;为2023年网络安全优秀创新成果大赛——成都分站赛暨四川省“熊猫杯”网络安全优秀作品大赛中获奖企业颁奖&#xff0c;天空卫士银行数据安全方案获得优秀解决方案奖。 本次比赛由四川…...

Swift学习笔记一(Array篇)

目录 0 绪论 1 数组的创建和初始化 2.数组遍历 2.1通过键值对遍历 2.2 通过forEach遍历 2.3 通过for in遍历 2.3.1 for in 搭配 enumerated 2.3.2 for in的另一种形式 2.3.2 for in 搭配 indices 2.4 通过Iterator遍历器遍历 3 数组的操作 3.1 contains 判断数组包含…...

C++项目实战——基于多设计模式下的同步异步日志系统-②-前置知识补充-不定参函数

文章目录 专栏导读不定参函数C风格不定参函数不定参宏函数 专栏导读 &#x1f338;作者简介&#xff1a;花想云 &#xff0c;在读本科生一枚&#xff0c;C/C领域新星创作者&#xff0c;新星计划导师&#xff0c;阿里云专家博主&#xff0c;CSDN内容合伙人…致力于 C/C、Linux 学…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...