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 美元。你必须给每个顾客正确找零&…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙
Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...