当前位置: 首页 > news >正文

编织梦想:SpringBoot AOP 教程与自定义日志切面完整实战

什么是 AOP

AOP 是指通过预编译方式和运行期动态代理的方式,在不修改源代码的情况下对程序进行功能增强的一种技术。AOP 不是面向对象编程(OOP)的替代品,而是 OOP 的补充和扩展。它是一个新的维度,用来表达横切问题,并提供一个声明式的处理方案。AOP 是 Spring 框架中的一个重要特性。

AOP 的使用场景

AOP 的使用场景一般是在某些纵向逻辑和多个相对独立的横向逻辑中,将横向逻辑进行抽象和封装,使得横向逻辑不再与纵向逻辑混杂在一起,使得应用程序更加易于维护和扩展。在实际开发中,AOP 的使用场景比较广泛,例如:

  • 日志记录:在应用程序中,可以通过 AOP 对方法调用进行拦截,在方法调用前后记录日志信息。
  • 安全处理:通过 AOP 实现安全方案,例如在应用程序中对某些敏感方法添加权限验证。
  • 性能监控:对应用程序进行性能监控,实现性能分析和调优。
  • 事物管理:通过 AOP 对事物进行管理,例如实现事物的回滚和提交。
  • 缓存管理:对应用程序进行缓存管理,例如在读写操作中进行缓存。

AOP 的核心概念

在学习 AOP 的过程中,有一些核心概念是相当重要的。

  1. 连接点(JointPoint)

连接点是程序中可能被拦截的方法。在 AOP 中,连接点是指所有被拦截到的方法。连接点包含两个信息:一个是方法的位置信息,另一个是方法的名称。

  1. 切点(Pointcut)

切点是一组连接点的集合,是要被拦截的连接点。在 Spring AOP 中,切点采用 AspectJ 的切点表达式进行描述,格式如 @Pointcut("execution(public * com.example.demo.controller.*.*(..))")

  1. 通知(Advice)

通知是指拦截到连接点后要执行的代码,包括 @Before@AfterReturning@AfterThrowing@After@Around 五种类型。

  1. 切面(Aspect)

切面是一个包含通知和切点的对象,主要用来维护切点和通知之间的关系。

  1. 织入(Weaving)

织入是将切面应用到目标对象来创建新的代理对象的过程。在 Spring AOP 中,织入可以在编译时、类加载时和运行时进行。

AOP 的实现方式

在 SpringBoot 中,AOP 的实现方式主要有两种:Java 代理(JDK Proxy)和字节码增强(CGLIB)。

  1. Java 代理(JDK Proxy)

Java 代理是一种基于接口的代理,通过实现 Java 动态代理接口 InvocationHandler 来实现对代理类方法的调用。Java 代理只能代理实现了接口的类,在运行时通过生成代理类的方式来实现。Java 代理的优点是操作简单,劣势是只能代理接口。

  1. 字节码增强(CGLIB)

字节码增强是一种基于继承的代理,通过生成代理类来完成对目标对象方法的调用。CGLIB 代理不需要实现接口,对目标对象进行继承并重写其中的方法,从而实现对方法的调用拦截。字节码增强的优点是能够代理非接口的类,劣势是需要引入 CGLIB 依赖包。

SpringBoot AOP 的例子

我们创建一个日志切面来记录调用方法开始时间、结束时间、持续时间等(方法名、参数、返回值…)。

pom.xml引入以下依赖包

<properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.3.7.RELEASE</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>${spring-boot.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring-boot.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>${spring-boot.version}</version></dependency></dependencies>

定义SysLog日志注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SysLog {String name() default "";
}

定义切面 LogAspect

@Aspect
public class LogAspect {// 定义需要被拦截的切点@Pointcut("execution(public * com.example.demo.controller.*.*(..))")public void pointcut() {}// 在方法执行时进行通知@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();SysLog sysLog = method.getAnnotation(SysLog.class);if (sysLog != null) {System.out.println("日志名称:" + sysLog.name());}System.out.println("开始时间:" + LocalDateTime.now());System.out.println("执行方法 " + joinPoint.getSignature().getName() + " 前置环绕通知");Object o = joinPoint.proceed();System.out.println("结束时间:" + LocalDateTime.now());System.out.println("执行方法 " + joinPoint.getSignature().getName() + " 后置环绕通知");return o;}// 在方法执行之前进行通知@Before("pointcut()")public void before(JoinPoint joinPoint) {System.out.println("执行方法 " + joinPoint.getSignature().getName() + " 前置通知");}// 在方法执行之后进行通知@After("pointcut()")public void after(JoinPoint joinPoint) {System.out.println("执行方法 " + joinPoint.getSignature().getName() + " 后置通知");}// 在方法执行之后返回结果时进行通知@AfterReturning(returning = "result", pointcut = "pointcut()")public void afterReturning(JoinPoint joinPoint, Object result) {System.out.println("执行方法 " + joinPoint.getSignature().getName() + " 返回通知,返回值:" + result);}// 在方法抛出异常时进行通知@AfterThrowing(throwing = "ex", pointcut = "pointcut()")public void afterThrowing(JoinPoint joinPoint, Exception ex) {System.err.println("执行方法 " + joinPoint.getSignature().getName() + " 异常通知,异常:" + ex.getMessage());}
}

整个通知流程如下:


注意:如下必须注入LogAspect Bean。

@Configuration
public class MyConfiguration {@Beanpublic LogAspect logAspect() {return new LogAspect();}
}

测试,在Controller方法上添加@SysLog(name = “这是一个日志名称”)注解。

@RestController()
@RequestMapping("user")
public class UserController {@SysLog(name = "这是一个日志名称")@GetMapping("test")public String test() {return "hello world";}
}

测试:访问 http://localhost:8080/user/test,打印如下结果:

日志名称:这是一个日志名称
开始时间:2023-07-17T16:33:11.935
执行方法 test 前置环绕通知
执行方法 test 前置通知
执行方法 test 返回通知,返回值:hello world
执行方法 test 后置通知
结束时间:2023-07-17T16:33:11.940
执行方法 test 后置环绕通知

总结

以上就是 SpringBoot AOP 的基本用法,通过使用 SpringBoot AOP,我们可以在不修改源代码的情况下对程序进行功能增强,实现对方法的拦截、日志记录、权限验证、性能监控等功能。

相关文章:

编织梦想:SpringBoot AOP 教程与自定义日志切面完整实战

什么是 AOP AOP 是指通过预编译方式和运行期动态代理的方式&#xff0c;在不修改源代码的情况下对程序进行功能增强的一种技术。AOP 不是面向对象编程&#xff08;OOP&#xff09;的替代品&#xff0c;而是 OOP 的补充和扩展。它是一个新的维度&#xff0c;用来表达横切问题&a…...

AssignableTypeFilter 和 AnnotationTypeFilter什么区别?

在 Spring 框架中&#xff0c;AssignableTypeFilter 和 AnnotationTypeFilter 都是用于在组件扫描过程中进行过滤的工具类&#xff0c;用于筛选出特定类型或特定注解的类。它们的主要区别在于筛选的侧重点和使用方式。 AssignableTypeFilter&#xff1a; AssignableTypeFilte…...

TCP-事件模型

#include "main.h"VOID Server_write_error() {}/*1.打开网络库 * 2.校验网络库版本 * 3.创建SOCKET * 4.绑定IP地址和端口 * 5.开始监听 * 6.创建客户端socket/接受链接 * 7.与客户端收发消息 * 8.(6.7)两步的函数accept&#xff0c;send,recv 有堵塞&#xff0c;可…...

typescript 声明文件

作用 1、为已存在js库提供类型信息&#xff0c;这样在ts项目中使用这些库时候&#xff0c;就像用ts一样&#xff0c;会有代码提示、类型保护等机制 2、项目内共享类型&#xff1a;如果多个.ts文件中都用到同一个类型&#xff0c;此时可以创建.d.ts文件提供该类型&#xff0c;…...

BC96 有序序列判断

描述 输入一个整数序列&#xff0c;判断是否是有序序列&#xff0c;有序&#xff0c;指序列中的整数从小到大排序或者从大到小排序(相同元素也视为有序)。 数据范围&#xff1a;3≤n≤50 序列中的值都满足1≤val≤100。 输入描述 第一行输入一个整数N(3≤N≤50)。 第二行…...

QT操作excel的两种方式 QT基础入门【Excel的操作】

QT操作excel的方式有两种&#xff1a;QAxObject 和QtXlsx QAxObject是通过调用office或者wps组件来实现对excel图表的操作的。只有装office软件或者wps软件就可以实现&#xff0c;但是 如果只装了office软件&#xff0c;有时可以用有时不可以用&#xff1b;如果只装wps软件&a…...

c++ qt--QString,弹出框(第二部分)

c qt–QString&#xff0c;弹出框&#xff08;第二部分&#xff09; 一.QString 1.所用头文件 #include<QString>2.功能 1.初始化 可以用字符&#xff0c;常量字符串、字符指针、字符数组等类型给QString进行初始化 QString str2"4567";//进行初始化2.拼…...

CSS自学框架之动画

这一节&#xff0c;自学CSS动画。主要学习了淡入淡出、淡入缩放、缩放、移动、旋转动画效果。先看一下成果。 优雅的过渡动画&#xff0c;为你的页面添加另一份趣味&#xff01; 在你的选择器里插入 animation 属性&#xff0c;并添加框架内置的 keyframes 即可实现&#xff0…...

RabbitMQ的5种消息队列

RabbitMQ的5种消息队列 1、七种模式介绍与应用场景 1.1 简单模式(Hello World) 一个生产者对应一个消费者&#xff0c;RabbitMQ 相当于一个消息代理&#xff0c;负责将 A 的消息转发给 B。 应用场景&#xff1a;将发送的电子邮件放到消息队列&#xff0c;然后邮件服务在队列…...

【C语言】选择排序

基本原理 先找到数组中最大的那个数&#xff0c;将最大的数放到数组最右端&#xff08;交换a[maxid]和a[len-1]这两个数的位置&#xff09;&#xff0c;然后继续从a[0]到a[len-2]中找到最大的数&#xff0c;然后交换a[maxid]和a[len-2]位置&#xff0c;依次查找交换&#xff0c…...

异步更新队列 - Vue2 响应式

前言 这篇文章分析了 Vue 更新过程中使用的异步更新队列的相关代码。通过对异步更新队列的研究和学习&#xff0c;加深对 Vue 更新机制的理解 什么是异步更新队列 先看看下面的例子&#xff1a; <div id"app"><div id"div" v-if"isShow&…...

【Unity的URP渲染管线下实现扩展后处理Volume组件_TemporalAntiAliasing(TAA)_抗锯齿(附带下载链接)】

【Unity的URP渲染管线下的TAA抗锯齿】 背景:1. Unity内置的抗锯齿只能够满足部分画面需求。展示一个锯齿示例。2. 在75寸大屏电视上跑通展示一个锯齿示例。- 在Camera上配置3. 安装了一个TAA组建,最后打包APK在安卓机上运行报错。- 经过测试排查,发现是没有将后处理的shader…...

NineData通过AWS FTR认证,打造安全可靠的数据管理平台

近日&#xff0c;NineData 作为新一代的云原生智能数据管理平台&#xff0c;成功通过了 AWS&#xff08;Amazon Web Service&#xff09;的 FTR 认证。NineData 在 FTR 认证过程中表现出色&#xff0c;成功通过了各项严格的测试和评估&#xff0c;在数据安全管理、技术应用、流…...

Qt应用开发(基础篇)——滚屏区域类 QScrollArea

一、前言 QScrollArea类继承于QAbstractScrollArea&#xff0c;QAbstractScrollArea继承于QFrame&#xff0c;是Qt滚动视图的常用部件。 滚屏区域基类 QAbstractScrollArea 框架类 QFrame QScrollArea类提供了对另一个小部件的滚动视图&#xff0c;基础功能、滚动条控制、界面策…...

安装最新版chromedriver 116,亲测可用

Version Selection...

html题库

什么是HTML? HTML的全称为 超文本标记语言 &#xff0c;是一种 标记语言 。 它包括一系列标签 &#xff0c;通过这些标签可以将网络上的文档格式统一&#xff0c;使分散的 Internet 资源连接为一个逻辑整体。 DOCTYPE 的作用是什么&#xff1f;标准模式与兼容模式&#xff08;…...

Android11 中 LED 使用-RK3568

文章目录 前言原理图设备树驱动前言 现在我们来学习点亮LED 原理图 然后对应在核心板原理图上查找 Working_LEDEN_H_GPIO0_B7,如下图所示: 那么我们只要控制 GPIO0_B7 即可控制 led 的亮灭。 设备树 leds: leds {compatible = "gpio-leds";work_led: work {gpi…...

BC77 有序序列插入一个数

描述 有一个有序数字序列&#xff0c;从小到大排序&#xff0c;将一个新输入的数插入到序列中&#xff0c;保证插入新数后&#xff0c;序列仍然是升序。 输入描述 第一行输入一个整数(0≤N≤50)。 第二行输入N个升序排列的整数&#xff0c;输入用空格分隔的N个整数。 第三…...

通过脚本使用Cppcheck做静态测试并生成报告(Windows)

1.安装cppcheck 先从cppcheck官方网站下载cppcheck的安装包。 注&#xff1a; &#xff08;1&#xff09;官网地址&#xff1a;https://sourceforge.net/projects/cppcheck &#xff08;2&#xff09;截止2023年8月&#xff0c;官方发布的最新版本是cppcheck-2.11-x64-Setup.…...

工业安全生产信息化平台的基本架构和关键功能分享

工业安全生产信息化平台是指利用信息技术手段&#xff0c;将工业安全生产管理与数据采集、传输、处理相结合&#xff0c;实现对工业安全生产全过程的数字化、信息化、智能化管理的平台。它通过集成多种信息系统和设备&#xff0c;实现对重大危险源监控预警、安全风险分级管控、…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

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

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

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...