当前位置: 首页 > 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 学…...

实战复盘:我是如何通过一个SSRF漏洞,利用Gopher协议拿下内网Redis的

从SSRF到内网Redis入侵&#xff1a;一次真实渗透测试的深度剖析 那天下午&#xff0c;我正在对某企业Web应用进行常规安全评估。一个看似普通的文件下载接口引起了我的注意——它接受URL参数并返回对应资源内容。直觉告诉我&#xff0c;这里可能存在SSRF漏洞。接下来的72小时&a…...

Windows键盘记录器:为什么需要、它是什么、以及如何正确使用

Windows键盘记录器&#xff1a;为什么需要、它是什么、以及如何正确使用 【免费下载链接】keylogger Keylogger for Windows. 项目地址: https://gitcode.com/gh_mirrors/keylogg/keylogger 在当今数字化时代&#xff0c;键盘记录器作为系统监控和用户行为分析工具&…...

【译】《心悟内核:先懂设计,再读代码》—1、内核并非进程,而是整个系统本身

作者&#xff1a;Moon Hee Lee 原文&#xff1a; The Kernel in the Mind 心悟内核:先懂设计&#xff0c;再读代码——内核并非进程&#xff0c;而是整个系统本身Linux 内核既不是普通进程、守护进程&#xff0c;也不是应用程序。它是一套常驻内存的高特权运行环境&#xff0c…...

告别手动配置!用Tcl脚本一键生成RFSoC RF-ADC/DAC IP核(Vivado 2023.2)

告别手动配置&#xff01;用Tcl脚本一键生成RFSoC RF-ADC/DAC IP核&#xff08;Vivado 2023.2&#xff09; 在FPGA开发中&#xff0c;RFSoC平台的RF数据转换器配置往往是项目迭代中最耗时的环节之一。每次新建工程或调整参数时&#xff0c;开发者都需要在Vivado GUI中重复点击数…...

E-Hentai智能下载器:零成本漫画管理效率革命

E-Hentai智能下载器&#xff1a;零成本漫画管理效率革命 【免费下载链接】E-Hentai-Downloader Download E-Hentai archive as zip file 项目地址: https://gitcode.com/gh_mirrors/eh/E-Hentai-Downloader 你是否曾为下载漫画而烦恼&#xff1f;面对心爱的作品&#xf…...

Java 100 天进阶之路 | 从入门到上岗就业 · 完整目录导航

&#x1f4da; Java 100 天进阶之路 | 从入门到上岗就业 完整目录导航 不背八股文&#xff0c;不堆概念。44篇基础56篇进阶&#xff0c;100天助你达到Java就业水平&#xff0c;从容面对技术面试。 零差评Java教程&#xff0c;从入门到微服务&#xff0c;每篇都有代码、避坑和面…...

图解UART串口通信:从电平标准到数据帧的完整解析

1. UART串口通信基础&#xff1a;从物理层到协议层 第一次接触嵌入式开发时&#xff0c;我被UART这个名字唬住了——Universal Asynchronous Receiver/Transmitter&#xff08;通用异步收发器&#xff09;&#xff0c;听起来像是某种高端设备。直到用USB转TTL模块点亮了第一个L…...

基于MCP协议构建监控数据连接器:统一多源数据赋能AI运维

1. 项目概述&#xff1a;一个面向开发者的监控数据连接器如果你是一名开发者&#xff0c;尤其是后端或运维工程师&#xff0c;那么“监控”这个词对你来说一定不陌生。从服务器CPU、内存使用率&#xff0c;到应用接口的响应时间、错误率&#xff0c;再到业务层面的关键指标&…...

基于多智能体协作的AI开发流程:三人团队模式解析与实践

1. 项目概述与核心痛点如果你和我一样&#xff0c;在日常开发中深度依赖像Claude这样的AI编码助手&#xff0c;那你一定也经历过那种“又爱又恨”的时刻。爱的是它强大的代码生成和理解能力&#xff0c;恨的是它时不时会“放飞自我”——比如你只想让它修改一个函数&#xff0c…...

告别生产翻车!用Altium Designer 21的DRC规则为你的PCB设计上好“保险”

Altium Designer 21 DRC规则深度实战&#xff1a;从设计规范到生产就绪的PCB 在硬件开发领域&#xff0c;PCB设计完成后到实际生产前的最后一道防线就是设计规则检查&#xff08;DRC&#xff09;。很多工程师将DRC视为简单的软件功能验证&#xff0c;但实际上&#xff0c;它承担…...