AOP使用场景记录总结(缓慢补充更新中)
测试项目结构:

目前是测试两个日志记录和 代码的性能测试 后面如果有其他的应用场景了在添加.其实一中就包括了二,但是没事,多练一遍
1. 日志记录
比如说对service层中的所有增加,删除,修改方法添加日志, 记录内容包括操作的时间 操作的方法, 方法的参数, 方法所在的类, 方法执行的时间. 等进行日志记录.后面可以把数据存到数据库中,也可以把数据存到日志文件中这里就简单的做一个演示,直接输出到控制台了.
对于AOP有两种方式可以实现, 由于注解较为灵活,所以这里就使用注解的方式来实现.如果不太会使用注解的方式,可以看一下我之前的笔记.
SpringAop中的五种常见的通知的注解及@annotation 切入点表达式_yfs1024的博客-CSDN博客
第一步: 定义注解
这里因为是对方法切入,所以创建了一个MethodLog注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodLog {
}
第二步: 在对应的方法上添加注解 这里是对Service层所以就加到Service上了
类如下: 其中包括增删改查, 因为我们要求的是对增删改进行日志记录,所以就把注解加到增删改的方法上即可
@Service
public class EmployeeServiceImpl implements EmployeeService {@Override@MethodLogpublic void insertEmployee(Employee employee) {System.out.println("新增");}@Override@MethodLogpublic void deleteEmployee(Long EmployeeId) {System.out.println("删除");}@Overridepublic List<Employee> list() {ArrayList<Employee> employees = new ArrayList<>();employees.add(new Employee());return employees;}@Override@MethodLogpublic void updateEmployee(Employee employee) {System.out.println("更新员工信息");}
}
第三步: 定义切面 定义切入点, 定义通知
@Aspect
@Component
@Slf4j
public class MyAspect {// 定义切入点 对那些方法进行切入// com.yfs1024.service任意子包下的任意类中任意参数,任意返回值 并且 使用@MethodLog注解的方法@Pointcut("execution(* com.yfs1024.service..*.*(..)) && @annotation(com.yfs1024.annocation.MethodLog)")public void pointCutForMethodLog() {}// 定义通知 做什么@Around("pointCutForMethodLog()")public Object methodLog(ProceedingJoinPoint joinPoint) throws Throwable {//操作时间LocalDateTime operateTime = LocalDateTime.now();//操作类名String className = joinPoint.getTarget().getClass().getName();//操作方法名String methodName = joinPoint.getSignature().getName();//操作方法参数Object[] args = joinPoint.getArgs();String methodParams = Arrays.toString(args);long begin = System.currentTimeMillis();// 为了防止时间太短,睡会Thread.sleep(3);//调用原始目标方法运行Object result = joinPoint.proceed();long end = System.currentTimeMillis();//操作耗时Long costTime = end - begin;log.info("方法操作时间{},方法所在类{},方法名{},方法的参数{},方法执行耗时 {}",operateTime,className,methodName,methodParams,costTime);
// 注意一定要返回return result;}}
第四步: 测试
在测试类中进行测试, 注意因为我们使用了Spring的注解所以一定要在测试类上加上@SpringBootTest 默认会加但是还是要注意一下.
测试方法如下:
@SpringBootTest
class SpringAopApplicationTests {@Autowiredprivate EmployeeService employeeService;@Testvoid methodLog() {Employee employee = new Employee();employeeService.insertEmployee(employee);employeeService.deleteEmployee(10001L);employeeService.list();employeeService.updateEmployee(employee);}
}
控制台结果:

嗯,真香 其实想想如果使用动态代理让我们自己写应该也能写出来这样的效果. 在之前的笔记中也有记录感兴趣的话可以看一下,在笔记的最后的案例中
试着让动态代理变得通俗易懂,通过三个案例_yfs1024的博客-CSDN博客
2. 性能测试.
需求: 现在有两个工具包, 分别是AliyunOssUtils 和 AliyunOssUtilsOld ,我们现在要通过AOP来对这两个工具包进行测试
你可能会问,就两个我还用AOP? 没错确实麻烦,但是这里就是举个例子. 后面如果多个的话我们只需要,修改切入点即可.
依然是上面的四步
第一步: 定义注解
// 性能测试日志记录
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PTLog {
}
第二步: 在对应的方法上添加注解 (也可以添加到,类上,但是其实还是执行方法的时候记录,因为有多个吗. 也可以是接口上,这样接口的实现类的所有的方法就都被切入了)
AliyunOssUtils
@Component
public class AliyunOssUtils {/*** 公共方法* @throws InterruptedException*/@PTLogpublic void load(MultipartFile multipartFile) throws InterruptedException {Thread.sleep(10);}
}
AliyunOssUtilsOld
@Component
public class AliyunOssUtilsOld {/*** 公共方法* @throws InterruptedException*/@PTLogpublic void load(MultipartFile multipartFile) throws InterruptedException {Thread.sleep(10);}
}
第三步: 定义切面 定义切入点, 定义通知
@Aspect
@Component
@Slf4j
public class MyAspect { // com.yfs1024.utils任意子包下的任意类中任意参数,任意返回值 并且 使用@PTLog注解的方法@Pointcut("execution(* com.yfs1024.utils..*.*(..)) && @annotation(com.yfs1024.annocation.PTLog)")public void pointCutForPTLog() {}@Around("pointCutForPTLog()")public Object ptLog(ProceedingJoinPoint joinPoint) throws Throwable {String className = joinPoint.getTarget().getClass().getName();long begin = System.currentTimeMillis();
// 为了防止时间太短,睡会Thread.sleep(3);//调用原始目标方法运行Object result = joinPoint.proceed();long end = System.currentTimeMillis();Long costTime = end - begin;log.info("{}类中方法执行耗时{}",className,costTime);return result;}
}
第四步: 测试
@SpringBootTest
class SpringAopApplicationTests {
// 这里因为测试用, 所以上面的工具类上就加了@Component注解, 一般不加哈,其实也可以通过一个配置类配合@Bean注入到容器这里懒了,嘿@Autowiredprivate AliyunOssUtils aliyunOssUtils;@Autowiredprivate AliyunOssUtilsOld aliyunOssUtilsOld;@Testvoid myPTLog() throws InterruptedException {aliyunOssUtils.load();aliyunOssUtilsOld.load();}
}
控制台结果:

3.公共字段的填充
首先介绍一下什么是公共字段的填充, 我们在对数据进行更新操作的时候,或者插入操作的时候往往都需要记录一下操作的时间, 基本所有的表都会有这两个字段,即 更新日期, 创建日期, 另外我们的每张表还需要记录创建该条记录的人是谁,以及修改这条记录的是谁,等这些就叫做公共字段. 对于不同的表可能要求不同视情况而定, 可见我们对于公共字段的操作往往是在 对数据库的更新操作和插入操作. 所以我们可以定义一个枚举来表示这两个操作,以供后期的使用.
第0步:
public enum OperationType {/*** 更新操作*/UPDATE,/*** 插入操作*/INSERT
}
第一步: 定义注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AutoFill {OperationType value() default OperationType.INSERT; // 设置枚举的参数,默认为插入操作
}
第二步: 在对应的方法上添加注解
这个时候就该想了, 我们把这些注解添在哪里合适?
答案是Mapper层, 因为Mapper层是和数据库交互的最后一个步骤, 我不管你之前怎么处理,知道在插入数据库之前把公共字段填充即可
代码如下:
@Mapper
public interface EmployeeMapper {/*** 根据用户名查询员工** @param username* @return*/@Select("select * from employee where username = #{username}")Employee getByUsername(String username);/*** @param employee*/
// @Options(useGeneratedKeys = true,keyProperty = "id")@AutoFill()void insertEmployee(Employee employee);/*** 根据条件查询用户列表** @param employee* @return*/Page<Employee> select(Employee employee);/*** 更新员工信息*/@AutoFill(OperationType.UPDATE)void updateEmployee(Employee employee);
}
此时对插入和更新操作添加注解:
第三步: 定义切面 定义切入点, 定义通知
此时AOP的强大就体现的淋漓尽致
@Component
@Aspect
@Slf4j
public class AutoFillAspect {// 设置通知的连接点所在的位置@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annocation.AutoFill)")public void insertOrUpdateCommonsMeg() {}// 当前切入位置是mapper层,所以是在方法执行之前,即Service层执行之后,再给公共的属性赋值@Before("insertOrUpdateCommonsMeg()")public void beforeAutoFillCommonsField(JoinPoint joinPoint) throws Exception {
// 获取连接点的方法对象Object[] args = joinPoint.getArgs();
// 判断如果不为空,再执行操作,如果为空直接返回if (args == null || args.length == 0) {return;}
// 此时就可以获取参数列表中的第一个对象,即为当前需要添加数据的对象Object NowMethodObject = args[0];Class<?> obj = NowMethodObject.getClass();
// 判断当前的方法是Insert还是Update那些方法进行切入MethodSignature signature = (MethodSignature) joinPoint.getSignature();AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class);
// 获取当前的注解对象,通过value值进行判断if (annotation.value() == OperationType.INSERT) {
// 获取创建时间方法这个对象Method setCreateTime = obj.getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
// 获取设置创建者id的方法对象Method setCreateUser = obj.getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
// 调用传入参数setCreateTime.invoke(NowMethodObject, LocalDateTime.now());setCreateUser.invoke(NowMethodObject, BaseContext.getCurrentId());}
// 其次我要知道对谁切入Method setUpdateTime = obj.getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
// 获取设置创建者id的方法对象Method setUpdateTUser = obj.getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
// 调用传入参数setUpdateTime.invoke(NowMethodObject, LocalDateTime.now());setUpdateTUser.invoke(NowMethodObject, BaseContext.getCurrentId());}
}
第四步: 测试
此时运行SpringBoot项目,进行更新和插入操作, 此时我们就可以看到数据库中的数据已经自动的填充进去

相关文章:
AOP使用场景记录总结(缓慢补充更新中)
测试项目结构: 目前是测试两个日志记录和 代码的性能测试 后面如果有其他的应用场景了在添加.其实一中就包括了二,但是没事,多练一遍 1. 日志记录 比如说对service层中的所有增加,删除,修改方法添加日志, 记录内容包括操作的时间 操作的方法, 方法的参数, 方法所在的类, 方法…...
FPGA基于XDMA实现PCIE X4的HDMI视频采集 提供工程源码和QT上位机程序和技术支持
目录1、前言2、我已有的PCIE方案3、PCIE理论4、总体设计思路和方案5、vivado工程详解6、驱动安装7、QT上位机软件8、上板调试验证9、福利:工程代码的获取1、前言 PCIE(PCI Express)采用了目前业内流行的点对点串行连接,比起 PCI …...
ArcGIS、ENVI、InVEST、FRAGSTATS等多技术融合提升环境、生态、水文、土地、土壤、农业、大气等领域的数据分析
查看原文>>>ArcGIS、ENVI、InVEST、FRAGSTATS等多技术融合提升环境、生态、水文、土地、土壤、农业、大气等领域的数据分析 目录 专题一、空间数据获取与制图 专题二、ArcGIS专题地图制作 专题三、空间数据采集与处理 专题四、遥感数据处理与应用 专题五、DEM数据…...
怎么找回回收站里已经删除的文件
作为忙忙碌碌的打工人,电脑办公是在所难免的,而将使电脑存储着大量的数据文件,不少小伙伴都养成了定期清理电脑的习惯。而清理简单快捷的方法,无疑是直接把文件拖进回收站里。再一键清空,清理工作就完成了。但如果发现…...
Spring Boot、Cloud、Alibaba 版本说明
Spring Boot、Cloud、Alibaba 版本说明 一、毕业版本依赖关系(推荐使用) 由于 Spring Boot 3.0,Spring Boot 2.7~2.4 和 2.4 以下版本之间变化较大,目前企业级客户老项目相关 Spring Boot 版本仍停留在 Spring Boot 2.4 以下,为了同时满足存…...
软件测试入门第一步:编写测试报告
什么是测试报告? 1、说明:是指把测试的过程和结果写成文档,对发现的问题和缺陷进行分析,为纠正软件的存在的质量问题提供依据,同时为软件验收和交付打下基础。 ps. 【测试过程和测试结果的分析报告,以及上线…...
【Vue】vue中的路由导航守卫(路由的生命周期)
文章目录全局前置守卫可选的第三个参数 next全局解析守卫router.beforeResolve全局后置钩子路由独享的守卫组件内的守卫可用的配置 API使用组合 API完整的导航解析流程正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入…...
NumPy 基础知识 :6~10
原文:Numpy Essentials 协议:CC BY-NC-SA 4.0 译者:飞龙 六、NumPy 中的傅立叶分析 除其他事项外,傅立叶分析通常用于数字信号处理。 这要归功于它在将输入信号(时域)分离为以离散频率(频域&am…...
实现vue的条件渲染
我的需求是根据设备不同的状态 渲染不同的标签。设备状态用device_State表示。 在线上面是一个vue的标签,我有一个数据state ,如何让这个标签根据数据的取值 ,修改内容,如state1时,标签修改为离线 要根据数据的取值动态…...
第四章 word2vec 的高速化
目录4.1 word2vec 的改进①4.1.1 Embedding 层4.1.2 Embedding 层的实现4.2 word2vec 的改进②4.2.1 中间层之后的计算问题4.2.2 从多分类到二分类4.2.3 sigmoid 函数和交叉熵误差4.2.4 多分类到二分类的实现4.2.5 负采样4.2.6 负采样的采样方法4.2.7 负采样的实现4.3 改进版 w…...
【四】3D Object Model之创建Creation——clear_object_model_3d()/copy_object_model_3d()算子
😊😊😊欢迎来到本博客😊😊😊 🌟🌟🌟 Halcon算子太多,学习查找都没有系统的学习查找路径,本专栏主要分享Halcon各类算子含义及用法,有…...
第三十一章 配置镜像 - 删除镜像成员时删除镜像数据库属性
文章目录第三十一章 配置镜像 - 删除镜像成员时删除镜像数据库属性删除镜像成员时删除镜像数据库属性编辑或删除异步成员第三十一章 配置镜像 - 删除镜像成员时删除镜像数据库属性 删除镜像成员时删除镜像数据库属性 当从镜像中删除成员时,始终可以选择从属于该镜…...
自动写作ai-自动写作神器
自动生成文章 自动生成文章是指使用自然语言处理和人工智能技术,通过算法来自动生成文章的过程。一些自动生成文章的工具可以使用大量数据,学习数据背后的语言规范和知识结构,从而生成高质量和有用的文章。这种技术能够减少写作时间和人力成…...
P1368 【模板】最小表示法(SAM 求最小循环移位)
【模板】最小表示法 题目描述 小敏和小燕是一对好朋友。 他们正在玩一种神奇的游戏,叫 Minecraft。 他们现在要做一个由方块构成的长条工艺品。但是方块现在是乱的,而且由于机器的要求,他们只能做到把这个工艺品最左边的方块放到最右边。…...
投票感知器参数学习算法
投票感知器参数学习算法 以下为投票感知器参数学习算法的伪代码: 输入:训练集 (x1,y1),(x2,y2),...,(xn,yn)(x_1, y_1), (x_2, y_2), ..., (x_n, y_n)(x1,y1),(x2,y2),...,(xn,yn),学习率 η\etaη,最大迭代次数 TTT…...
Hyper-v下安装CentOS-Stream-9
1、我不想要动态扩展的硬盘,固定大小硬盘性能更高,所以这里我先创建一个固定硬盘(如果你想用动态扩展的硬盘,那么可以省略前面几步,直接从第7步开始,并在第12步选择创建可动态扩展的虚拟硬盘)&a…...
数据结构之顺序表,实现顺序表的增删改查
目录 一、顺序表的概念 二、顺序表的分类 1.静态顺序表 2.动态顺序表 3.顺序表的增删改查 总结 一、顺序表的概念 顺序表是一段物理地址连续的村塾单元依次存储数据元素的线性结构,一般情况下使用数组存储,在数组上完成数据的增删改查。 二、顺…...
HTB-Jeeves
HTB-Jeeves信息收集80端口50000端口开机kohsuke -> Administrator信息收集 80端口 ask jeeves是一款以回答用户问题提问的自然语言引擎,面对问题首先查看数据库里是否…...
大力出奇迹——GPT系列论文学习(GPT,GPT2,GPT3,InstructGPT)
目录说在前面1.GPT1.1 引言1.2 训练范式1.2.1 无监督预训练1.2.2 有监督微调1.3 实验2. GPT22.1 引言2.2 模型结构2.3 训练范式2.4 实验3.GPT33.1引言3.2 模型结构3.3 训练范式3.4 实验3.4.1数据集3.5 局限性4. InstructGPT4.1 引言4.2 方法4.2.1 数据收集4.2.2 各部分模型4.3 …...
Linux ubuntu更新meson版本
问题描述 在对项目源码用meson进行编译时,可能出现以下错误 meson.build:1:0: ERROR: Meson version is 0.45.1 but project requires > 0.58.0. 或者 meson_options.txt:1:0: ERROR: Unknown type feature. 等等,原因是meson版本跟设置的不适配。 …...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
