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

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent

安全大模型训练计划&#xff1a;基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标&#xff1a;为安全大模型创建高质量、去偏、符合伦理的训练数据集&#xff0c;涵盖安全相关任务&#xff08;如有害内容检测、隐私保护、道德推理等&#xff09;。 1.1 数据收集 描…...