Spring AOP基于注解方式实现和细节

目录
一、Spring AOP底层技术
二、初步实现AOP编程
三、获取切点详细信息
四、 切点表达式语法
五、重用(提取)切点表达式
一、Spring AOP底层技术
SpringAop的核心在于动态代理,那么在SpringAop的底层的技术是依靠了什么技术呢?

- 动态代理(InvocationHandler):JDK原生的实现方式,需要被代理的目标类必须实现接口。因为这个技术要求代理对象和目标对象实现同样的接口(兄弟两个拜把子模式)。
- cglib:通过继承被代理的目标类实现代理,所以不需要目标类实现接口。
- AspectJ:早期的AOP实现的框架,SpringAOP借用了AspectJ中的AOP注解。
二、初步实现AOP编程
2.1实现AOP需要以下注解:
| 注解 | 说明 |
|---|---|
| @SpringJUnitConfig | 在JUnit测试类中使用Spring测试上下文配置 |
| @Aspect | 将类标记为切面类,定义切面逻辑和增强方法的位置 |
| @EnableAspectJAutoProxy | 开启AspectJ自动代理,用于启用Spring AOP的功能 |
2.2需要导入以下依赖
<!-- 切面实现 --><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.6</version>
</dependency>
<!-- spring核心 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency>
<!-- spring-test容器测试 --><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>6.0.6</version><scope>test</scope></dependency>
2.3 增强(通知)注解
| 注解 | 说明 |
|---|---|
| @Before | 在目标方法执行前执行的增强逻辑 |
| @AfterReturning | 在目标方法成功返回后执行的增强逻辑 |
| @AfterThrowing | 在目标方法抛出异常后执行的增强逻辑 |
| @After | 在目标方法执行后执行的增强逻辑 |
| @Around | 包裹目标方法,在目标方法执行前后都可以执行自定义的增强逻辑 |
实现增强(通知)的步骤
- 定义方法存储增强代码
- 使用注解配置,指定插入目标的位置
- 配置切点表达式(选中插入的方法,切点)
- 补全注解,加入到ioc容器,并且设置切面@Aspect
- 开启Aspect注解注释
案例代码:
//4.补全注解
@Component
@Aspect//1.创建增强类与增强方法start(),after,Error
public class advice {// 2.使用注解配置,配置插入位置@Before @After @AfterThrowing
// 3.配入切点表达式execution(* com.alphamilk.Impl.*.*(..))表明需要插入的方法为所有com.alhpamilk.Impl包下所有类的所有方法@Before("execution(* com.alphamilk.Impl.*.*(..))")public void start(){System.out.println("方法起始处插入");}@After("execution(* com.alphamilk.Impl.*.*(..))")public void after(){System.out.println("方法结束后插入");}@AfterThrowing("execution(* com.alphamilk.Impl.*.*(..))")public void Error(){System.out.println("方法异常时候插入");}
}
@ComponentScan(value = "com.alphamilk")
@Configuration
//6.注解类中开启注解注释
@EnableAspectJAutoProxy
public class JavaConfig {
}

三、获取切点详细信息
虽然已经初步实现了AOP的实现,但是还不够,在调用多个方法时候如果都是输入,调用方法前,调用方法后等等,这样并不能区分是调用了哪个方法,所以为了区分我们需要获取调用这个方法的相关信息,比如参数,方法名,返回值等等。
具体实现方式:
通过JoinPoint接口的下面几个方法获取
| 方法 | 说明 |
|---|---|
| getTarget() | 获取被代理的目标对象 |
| getClass() | 获取被代理的目标对象的类 |
| getSimpleName() | 获取被代理的目标对象的简单类名(不含包名) |
| getArgs() | 获取方法参数数组 |
| getSignature() | 获取方法签名,包括方法名、返回类型、参数类型等信息 |
| getModifiers() | 获取方法修饰符 |
有三个案例分别是一般情况,需要返回值情况,还有异常情况
一般情况(前置通知、后置通知)
案例代码:
需要在方法调用中参数加入JoinPoint接口实例化对象用以创建对应的动态代理,并通过动态代理获取对象相关信息。
public class advice {@Before("execution(* com.alphamilk.*.*(..))")public void Before(JoinPoint joinPoint) {
// 获取类名String simpleName = joinPoint.getTarget().getClass().getSimpleName();
// 获取方法修饰符int modifiers = joinPoint.getSignature().getModifiers();String Moidfier = Modifier.toString(modifiers);
// 获取方法名称String name = joinPoint.getSignature().getName();
// 获取参数Object[] args = joinPoint.getArgs();
//System.out.println("调用的方法是" + name);System.out.println("调用的类是" + simpleName);for (Object arg : args) {System.out.println(arg);}System.out.println("调用方法前");}@After("execution(* com.alphamilk.*.*(..))")public void After(JoinPoint joinPoint) {System.out.println("调用方法后");}
}
有返回值的情况(返回通知)
在一般情况的前提下,还需要多增加Object result参数用以接收返回值.和注解增加returning输入确切的返回对象的名称。
案例代码
public class advice {@AfterReturning(value = "execution(* com.alphamilk.*.*(..))",returning = "result")public void AfterReturning(JoinPoint joinPoint,Object result) {System.out.println("调用拥有返回值的方法");System.out.println("获取到的返回值为"+result);}
}

异常情况(异常通知)
异常通知,获取异常信息,需要在一般情况的前提下,在注解中多声明一个注解throwing,在方法参数增加一个Throwable对象,并且throwing注解对应的值就是Throwable的对象名称。
案例代码:
@AfterThrowing(value = "execution(* com.alphamilk.*.*(..))",throwing = "throwable")public void AfterThrowing(JoinPoint joinPoint,Throwable throwable) {System.out.println("调用有异常的方法");System.out.println("异常对象为"+throwable.getClass().getName());}
@SpringJUnitConfig(value = JavaConfig.class)
public class newaopTest {@Autowiredprivate Caculate caculate;@Testpublic void Test(){caculate.div(2,0);}
}

四、 切点表达式语法
1.切点表达式作用
AOP切点表达式(Pointcut Expression)是一种用于指定切点的语言,它可以通过定义匹配规则,来选择需要被切入的目标对象。

2.切点表达式语法

-
具体值:
- (String, int):第一个参数是字符串,第二个参数是整数。
- (int, String):第一个参数是整数,第二个参数是字符串。
- ():没有参数。
-
模糊值:
- (..):任意参数,有或者没有。
-
部分具体和模糊:
- (String..):第一个参数是字符串,后面可能有其他参数。
- (..String):最后一个参数是字符串,前面可能有其他参数。
- (String..int):字符串开头,最后一个参数是整数,中间可能有其他参数。
- (..int..):包含整数类型的参数,位置不限,可能有其他参数。
具体实战案例:
1.查询某包某类下,访问修饰符是公有,返回值是int的全部方法
execution public int 某包.某类.*(..)
2.查询某包下类中第一个参数是String的方法
execution * 某包.某类.*(String..)
3.查询全部包下,无参数的方法!
execution * *..*.*( )
4.查询com包下,以int参数类型结尾的方法
execution * com..*.*(..int)
5.查询指定包下,Service开头类的私有返回值int的无参数方法
execution private int 指定包.Service*.*()
五、重用(提取)切点表达式
如果在每一个方法前都加上一个固定的切点表达式,那么将会十分麻烦,所以下面介绍切点表达式的重用
1.在当前类中提取
特定注解@Pointcut
| 注解 | 描述 |
|---|---|
@Pointcut | 声明切点表达式的方法,用于定义切点的匹配规则。 |
通过定义一个空方法,使用@Pointcut注解并带上特定的切点表达式
案例代码:
@Component
@Aspect
public class advice {/*定义空方法空方法上加上注解@Pointcut并带上相应的切点表达式在其他增强方法上调用方法*/@Pointcut("execution(* com.alphamilk.*.*(..))" )public void blank(){}@Before("blank()")public void Before(JoinPoint joinPoint) {System.out.println("调用方法前");}@After("blank()")public void After(JoinPoint joinPoint) {System.out.println("调用方法后");}@AfterReturning(value = "blank()",returning = "result")public void AfterReturning(JoinPoint joinPoint,Object result) {System.out.println("调用拥有返回值的方法");}@AfterThrowing(value = "blank()",throwing = "throwable")public void AfterThrowing(JoinPoint joinPoint,Throwable throwable) {System.out.println("调用有异常的方法");}
}
2.创建一个存储切点类
(推荐)通过创建一个单独的存储切点的类,更加容易进行维护表达式
使用时候加上特定类的方法名即可
案例:
存储切点的类
@Component
public class MyPointcut {@Pointcut("execution(* com.alphamilk.Impl.*.*(..))")public void pointcut1(){}
}
对应引用类
@Component
@Aspect
public class advice {@Before("com.alphamilk.Advice.MyPointcut.pointcut1()")public void Before(JoinPoint joinPoint) {System.out.println("调用方法前");}@After("com.alphamilk.Advice.MyPointcut.pointcut1()")public void After(JoinPoint joinPoint) {System.out.println("调用方法后");}@AfterReturning(value = "com.alphamilk.Advice.MyPointcut.pointcut1()",returning = "result")public void AfterReturning(JoinPoint joinPoint,Object result) {System.out.println("调用拥有返回值的方法");}@AfterThrowing(value = "com.alphamilk.Advice.MyPointcut.pointcut1()",throwing = "throwable")public void AfterThrowing(JoinPoint joinPoint,Throwable throwable) {System.out.println("调用有异常的方法");}
}
本章总结
1.SpringAop底层技术
了解底层代理技术有jdk 与 cglib
2.初步实现AOP编程
掌握增强注解(@Before、@AfterReturning、@AfterThrowing、@After、@Around)
掌握@Aspect注解的使用
3.获取切点详细信息
掌握如何通过JoinPoint接口对象获取对应方法的类,方法名称,参数,方法修饰符
掌握三种不同情况下获取对应信息的情况(一般情况、返回通知、异常通知)
4.切点表达式语法
熟悉切点表达式的格式
(execution +权限修饰 +方法返回值类型+方法所在全类名+方法名称+参数列表)
5.重用(提取)切点表达式
相关文章:
Spring AOP基于注解方式实现和细节
目录 一、Spring AOP底层技术 二、初步实现AOP编程 三、获取切点详细信息 四、 切点表达式语法 五、重用(提取)切点表达式 一、Spring AOP底层技术 SpringAop的核心在于动态代理,那么在SpringAop的底层的技术是依靠了什么技术呢&#x…...
CVPR2023论文及代码合集来啦~
以下内容由马拉AI整理汇总。 下载:点我跳转。 狂肝200小时的良心制作,529篇最新CVPR2023论文及其Code,汇总成册,制作成《CVPR 2023论文代码检索目录》,包括以下方向: 1、2D目标检测 2、视频目标检测 3、…...
基于ETLCloud的自定义规则调用第三方jar包实现繁体中文转为简体中文
背景 前面曾体验过通过零代码、可视化、拖拉拽的方式快速完成了从 MySQL 到 ClickHouse 的数据迁移,但是在实际生产环境,我们在迁移到目标库之前还需要做一些过滤和转换工作;比如,在诗词数据迁移后,发现原来 MySQL 中…...
TDesign在按钮上加入图标组件
在实际开发中 我们经常会遇到例如 添加或者查询 我们需要在按钮上加入图标的操作 TDesign自然也有预备这样的操作 首先我们打开文档看到图标 例如 我们先用某些图标 就可以点开下面的代码 可以看到 我们的图标大部分都是直接用tdesign-icons-vue 导入他的组件就可以了 而我…...
Linux 终端命令行 产品介绍
Linux命令手册内置570多个Linux 命令,内容包含 Linux 命令手册。 【软件功能】: 文件传输 bye、ftp、ftpcount、ftpshut、ftpwho、ncftp、tftp、uucico、uucp、uupick、uuto、scp备份压缩 ar、bunzip2、bzip2、bzip2recover、compress、cpio、dump、gun…...
计算机毕设 基于深度学习的植物识别算法 - cnn opencv python
文章目录 0 前言1 课题背景2 具体实现3 数据收集和处理3 MobileNetV2网络4 损失函数softmax 交叉熵4.1 softmax函数4.2 交叉熵损失函数 5 优化器SGD6 最后 0 前言 🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点&a…...
【STM32】学习笔记-江科大
【STM32】学习笔记-江科大 1、STM32F103C8T6的GPIO口输出 2、GPIO口输出 GPIO(General Purpose Input Output)通用输入输出口可配置为8种输入输出模式引脚电平:0V~3.3V,部分引脚可容忍5V输出模式下可控制端口输出高低电平&#…...
Doris架构中包含哪些技术?
Doris主要整合了Google Mesa(数据模型),Apache Impala(MPP Query Engine)和Apache ORCFile (存储格式,编码和压缩)的技术。 为什么要将这三种技术整合? Mesa可以满足我们许多存储需求的需求,但是Mesa本身不提供SQL查询引擎。 Impala是一个…...
《vue3实战》通过indexOf方法实现电影评价系统的模糊查询功能
目录 前言 一、indexOf是什么?indexOf有什么作用? 含义: 作用: 二、功能实现 这段是查询过程中过滤筛选功能的代码部分: 分析: 这段是查询用户和性别功能的代码部分: 分析: 三、最终效…...
java对时间序列每x秒进行分组
问题:将一个时间序列每5秒分一组,返回嵌套的list; 原理:int除int会得到一个int(也就是损失精度) 输入:排序后的list,每几秒分组值 private static List<List<Long>> get…...
八月更新 | CI 构建计划触发机制升级、制品扫描 SBOM 分析功能上线!
点击链接了解详情 这个八月,腾讯云 CODING DevOps 对持续集成、制品管理、项目协同、平台权限等多个产品模块进行了升级改进,为用户提供更灵活便捷的使用体验。以下是 CODING 新功能速递,快来看看是否有您期待已久的功能特性: 01…...
Spring核心配置步骤-完全基于XML的配置
Spring框架的核心配置涉及多个方面,包括依赖注入(DI)、面向切面编程(AOP)等。以下是一般情况下配置Spring应用程序的核心步骤: 1. **引入Spring依赖:** 在项目的构建工具(如Maven、…...
宏基官网下载的驱动怎么安装(宏基笔记本如何安装系统)
本文为大家介绍宏基官网下载的驱动怎么安装宏基笔记本驱动(宏基笔记本如何安装系统),下面和小编一起看看详细内容吧。 宏碁笔记本怎么一键更新驱动 1. 单击“开始”,然后选择“所有程序”。 2. 单击Acer,然后单击Acer eRecovery Management。…...
基于AVR128单片机抢答器proteus仿真设计
一、系统方案 二、硬件设计 原理图如下: 三、单片机软件设计 1、首先是系统初始化 void timer0_init() //定时器初始化 { TCCR00x07; //普通模式,OC0不输出,1024分频 TCNT0f_count; //初值,定时为10ms TIFR0x01; //清中断标志…...
openGauss学习笔记-54 openGauss 高级特性-MOT
文章目录 openGauss学习笔记-54 openGauss 高级特性-MOT54.1 MOT特性及价值54.2 MOT关键技术54.3 MOT应用场景54.4 不支持的数据类型54.5 使用MOT54.6 将磁盘表转换为MOT openGauss学习笔记-54 openGauss 高级特性-MOT openGauss引入了MOT(Memory-Optimized Table&…...
InsCode AI 创作助手
RESTful API是一种架构风格和设计原则,用于构建Web服务和应用程序。它基于HTTP协议,以资源为中心,对资源进行各种操作。RESTful API的主要特点包括: 使用HTTP协议进行传输和通信;操作和状态均以资源为中心;…...
java对时间序列根据阈值进行连续性分片
问题描述:我需要对一个连续的时间戳list进行分片,分片规则是下一个数据比当前数据要大于某一个阈值则进行分片; 解决方式: 1、输入的有顺序的list ,和需要进行分片的阈值 2、调用方法,填入该排序的list和阈…...
Pillow:Python的图像处理库(安装与使用教程)
在Python中,Pillow库是一个非常强大的图像处理库。它提供了广泛的图像处理功能,让我们可以轻松地操作图像,实现图像的转换、裁剪、缩放、旋转等操作。此外,Pillow还支持多种图像格式的读取和保存,包括JPEG、PNG、BMP、…...
自然语言处理-NLP
目录 自然语言处理-NLP 致命密码:一场关于语言的较量 自然语言处理的发展历程 兴起时期 符号主义时期 连接主义时期 深度学习时期 自然语言处理技术面临的挑战 语言学角度 同义词问题 情感倾向问题 歧义性问题 对话/篇章等长文本处理问题 探索自然语言…...
柠檬水找零【贪心算法-】
柠檬水找零 在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零&…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
