【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 中的 AOP:实现日志记录与性能监控

 <前文回顾>

点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshare=blogcolumn&sharetype=blogcolumn&sharerId=12907601&sharerefer=PC&sharesource=FoyoDesigner&sharefrom=from_link

<今日更新>

一、开篇整活儿

今儿个咱唠唠 Spring Boot 里头的 AOP(面向切面编程)。这玩意儿吧,说大不大,说小不小,整好了是锦上添花,整不好就是火上浇油。你要是刚入门,那可得悠着点儿,别一上来就整得自己“翻车”了。

二、AOP 是啥玩意儿?

AOP 是 Spring 里头的一个高级特性,用来在不修改原有代码的情况下,给程序动态添加功能。比如说,你可以用 AOP 来记录日志、监控性能、处理异常啥的。Spring Boot 里头默认就集成了这玩意儿,用起来贼方便。

1. AOP 的核心概念

AOP 里头有几个核心概念:切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)。

  • 切面:就是你要添加的功能,比如说日志记录、性能监控啥的。
  • 连接点:就是程序执行过程中的某个点,比如说方法调用、异常抛出啥的。
  • 通知:就是切面在连接点执行的动作,比如说在方法调用前记录日志。
  • 切点:就是用来匹配连接点的表达式,比如说匹配某个包下的所有方法。

2. AOP 的通知类型

AOP 里头有五种通知类型:

  • 前置通知(Before):在连接点之前执行。
  • 后置通知(After):在连接点之后执行,不管连接点是否抛出异常。
  • 返回通知(AfterReturning):在连接点正常返回后执行。
  • 异常通知(AfterThrowing):在连接点抛出异常后执行。
  • 环绕通知(Around):在连接点前后都执行,可以控制连接点的执行。

三、用 AOP 实现日志记录

日志记录是 AOP 的经典应用场景。你可以用 AOP 来记录方法的调用信息,方便以后排查问题。

1. 定义切面

首先,你得定义一个切面,用 @Aspect 注解标记。

Java Code

@Aspect

@Component

public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

}

这段代码里头,LoggingAspect 是一个切面,@Aspect 注解标记了这个类,@Component 注解让 Spring 管理这个类。

2. 定义切点

然后,你得定义一个切点,用 @Pointcut 注解标记。

Java Code

@Aspect

@Component

public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

    @Pointcut("execution(* com.example.demo.service.*.*(..))")

    public void serviceMethods() {}

}

这段代码里头,serviceMethods 是一个切点,execution(* com.example.demo.service.*.*(..)) 表示匹配 com.example.demo.service 包下的所有方法。

3. 定义通知

最后,你得定义通知,用 @Before、@After、@AfterReturning、@AfterThrowing 或 @Around 注解标记。

Java Code

@Aspect

@Component

public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

    @Pointcut("execution(* com.example.demo.service.*.*(..))")

    public void serviceMethods() {}

    @Before("serviceMethods()")

    public void logMethodCall(JoinPoint joinPoint) {

        logger.info("调用方法:{}", joinPoint.getSignature().getName());

    }

}

这段代码里头,logMethodCall 是一个前置通知,@Before 注解标记了这个方法,JoinPoint 参数用来获取连接点的信息。

四、用 AOP 实现性能监控

性能监控是 AOP 的另一个经典应用场景。你可以用 AOP 来记录方法的执行时间,方便以后优化性能。

1. 定义切面

首先,你得定义一个切面,用 @Aspect 注解标记。

Java Code

@Aspect

@Component

public class PerformanceAspect {

    private static final Logger logger = LoggerFactory.getLogger(PerformanceAspect.class);

}

这段代码里头,PerformanceAspect 是一个切面,@Aspect 注解标记了这个类,@Component 注解让 Spring 管理这个类。

2. 定义切点

然后,你得定义一个切点,用 @Pointcut 注解标记。

Java Code

@Aspect

@Component

public class PerformanceAspect {

    private static final Logger logger = LoggerFactory.getLogger(PerformanceAspect.class);

    @Pointcut("execution(* com.example.demo.service.*.*(..))")

    public void serviceMethods() {}

}

这段代码里头,serviceMethods 是一个切点,execution(* com.example.demo.service.*.*(..)) 表示匹配 com.example.demo.service 包下的所有方法。

3. 定义通知

最后,你得定义通知,用 @Around 注解标记。

Java Code

@Aspect

@Component

public class PerformanceAspect {

    private static final Logger logger = LoggerFactory.getLogger(PerformanceAspect.class);

    @Pointcut("execution(* com.example.demo.service.*.*(..))")

    public void serviceMethods() {}

    @Around("serviceMethods()")

    public Object measureMethodExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {

        long startTime = System.currentTimeMillis();

        Object result = joinPoint.proceed();

        long endTime = System.currentTimeMillis();

        logger.info("方法 {} 执行时间:{} 毫秒", joinPoint.getSignature().getName(), endTime - startTime);

        return result;

    }

}

这段代码里头,measureMethodExecutionTime 是一个环绕通知,@Around 注解标记了这个方法,ProceedingJoinPoint 参数用来控制连接点的执行。

五、AOP 的坑点

1. 切点表达式写错了

AOP 里头,切点表达式写错了,那通知就不起作用了。你要是写错了,那可得好好检查检查。

Java Code

@Pointcut("execution(* com.example.demo.service.*.*(..))") // 写错了

public void serviceMethods() {}

这段代码里头,execution 写错了,应该是 execution。

当然,写不好表达式,可以问AI啊。

2. 通知顺序不对

AOP 里头,通知顺序不对,那结果就不对了。你要是顺序不对,那可得好好调整调整。

Java Code

@Before("serviceMethods()")

public void logMethodCall(JoinPoint joinPoint) {

    logger.info("调用方法:{}", joinPoint.getSignature().getName());

}

@Around("serviceMethods()")

public Object measureMethodExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {

    long startTime = System.currentTimeMillis();

    Object result = joinPoint.proceed();

    long endTime = System.currentTimeMillis();

    logger.info("方法 {} 执行时间:{} 毫秒", joinPoint.getSignature().getName(), endTime - startTime);

    return result;

}

这段代码里头,logMethodCall 和 measureMethodExecutionTime 的顺序很重要。

3. 切面没被 Spring 管理

AOP 里头,切面没被 Spring 管理,那通知就不起作用了。你要是没被管理,那可得好好检查检查。

Java Code

@Aspect // 没加 @Component

public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

    @Pointcut("execution(* com.example.demo.service.*.*(..))")

    public void serviceMethods() {}

    @Before("serviceMethods()")

    public void logMethodCall(JoinPoint joinPoint) {

        logger.info("调用方法:{}", joinPoint.getSignature().getName());

    }

}

这段代码里头,LoggingAspect 没加 @Component 注解,Spring 不会管理这个类。

、额外再说一点

对于大多数 Spring Boot 项目,如果你只是简单地使用 AOP 来实现日志记录、事务管理等功能,并且已经引入了 spring-boot-starter-aop 依赖,那么通常不需要显式地使用 @EnableAspectJAutoProxy 注解。Spring Boot 会自动为你处理相关的配置。

然而,如果你有特殊的需求,比如自定义代理创建策略或确保 AOP 支持被启用,那么你可以考虑显式地使用 @EnableAspectJAutoProxy 注解

专有名词解释

  1. AOP:面向切面编程,一种编程范式,用来在不修改原有代码的情况下,给程序动态添加功能。
  2. 切面:AOP 里头的一个概念,表示你要添加的功能。
  3. 连接点:AOP 里头的一个概念,表示程序执行过程中的某个点。
  4. 通知:AOP 里头的一个概念,表示切面在连接点执行的动作。
  5. 切点:AOP 里头的一个概念,表示用来匹配连接点的表达式。
  6. 前置通知:AOP 里头的一种通知类型,在连接点之前执行。
  7. 后置通知:AOP 里头的一种通知类型,在连接点之后执行。
  8. 返回通知:AOP 里头的一种通知类型,在连接点正常返回后执行。
  9. 异常通知:AOP 里头的一种通知类型,在连接点抛出异常后执行。
  10. 环绕通知:AOP 里头的一种通知类型,在连接点前后都执行。
  11. JoinPoint:AOP 里头的一个接口,用来获取连接点的信息。
  12. ProceedingJoinPoint:AOP 里头的一个接口,用来控制连接点的执行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/899632.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TCP/IP协议簇

文章目录 应用层http/httpsDNS补充 传输层TCP1. 序列号与确认机制2. 超时重传3. 流量控制&#xff08;滑动窗口机制&#xff09;4. 拥塞控制5. 错误检测与校验6. 连接管理总结 网络层ARP**ARP 的核心功能**ARP 的工作流程1. ARP 请求&#xff08;Broadcast&#xff09;2. ARP 缓…

SpringBoot分布式项目订单管理实战:Mybatis最佳实践全解

一、架构设计与技术选型 典型分布式订单系统架构&#xff1a; [网关层] → [订单服务] ←→ [分布式缓存]↑ ↓ [用户服务] [支付服务]↓ ↓ [MySQL集群] ← [分库分表中间件]技术栈组合&#xff1a; Spring Boot 3.xMybatis-Plus 3.5.xShardingSpher…

微服务架构中的精妙设计:环境和工程搭建

一.前期准备 1.1开发环境安装 Oracle从JDK9开始每半年发布⼀个新版本, 新版本发布后, ⽼版本就不再进⾏维护. 但是会有⼏个⻓期维护的版本. ⽬前⻓期维护的版本有: JDK8, JDK11, JDK17, JDK21 在 JDK版本的选择上&#xff0c;尽量选择⻓期维护的版本. 为什么选择JDK17? S…

Maven 构建配置文件详解

Maven 构建配置文件详解 引言 Maven 是一个强大的项目管理和构建自动化工具,广泛应用于 Java 开发领域。在 Maven 项目中,配置文件扮演着至关重要的角色。本文将详细介绍 Maven 构建配置文件的相关知识,包括配置文件的作用、结构、配置方法等,帮助读者更好地理解和应用 M…

【YOLO系列】基于YOLOv8的无人机野生动物检测

基于YOLOv8的无人机野生动物检测 1.前言 在野生动物保护、生态研究和环境监测领域&#xff0c;及时、准确地检测和识别野生动物对于保护生物多样性、预防人类与野生动物的冲突以及制定科学的保护策略至关重要。传统的野生动物监测方法通常依赖于地面巡逻、固定摄像头或无线传…

Hive UDF开发实战:构建高性能JSON生成器

目录 一、背景与需求场景 二、开发环境准备 2.1 基础工具栈 2.2 Maven依赖配置 三、核心代码实现

分布式特性对比

以下是关于 分片(Sharding)、一致性哈希、两阶段提交(2PC)、Paxos、Raft协议、数据局部性 的对比分析与关联性总结,涵盖核心机制、适用场景及相互关系: 一、概念对比与关联 概念核心目标关键特性典型应用场景与其它技术的关联分片(Sharding)数据水平拆分按规则(哈希、…

历史分钟高频数据

外盘期货高频分钟历史回测行情数据下载 链接: https://pan.baidu.com/s/1RUbAMxfiSyBlXfrwT_0n2w?pwdhgya 提取码: hgya通过美国期货高频交易所历史行情可以看到很多细节比如品种之一&#xff1a;FGBX_1min (1)在2024-02-29 11:14:00关键交易时刻&#xff0c;一笔大规模订单突…

final+模版设计模式的理解

模板设计模式在 Java 里是一种行为设计模式&#xff0c;它在抽象类里定义算法的骨架&#xff0c;把部分步骤的具体实现延迟到子类。如此一来&#xff0c;子类可以在不改变算法结构的基础上&#xff0c;重新定义算法中的特定步骤。 模式组成 抽象类&#xff08;Abstract Class…

JAVA接口调用限速器

目录 1、并发限速 2、串行限速 需求&#xff1a;批量调用第三方ERP接口&#xff0c;对方接口限流时&#xff0c;减缓调用速率。 1、并发限速 Slf4j RestController public class ApiCallTask {//第三方接口Resourceprivate ErpService erpService;//异步线程池Resourcepriv…

STM32 CAN控制器硬件资源与用法

1、硬件结构图 以STM32F4为例&#xff0c;他有2个can控制器&#xff0c;分别为 CAN1 CAN2。 每个CAN控制器&#xff0c;都有3个发送邮箱、2个接收fifo&#xff0c;每个接收fifo又由3个接收邮箱组成。也即每个CAN控制器都有9个邮箱&#xff0c;其中3个供发送用&#xff0c;3个…

【C++ 继承】—— 青花分水、和而不同,继承中的“明明德”与“止于至善”

欢迎来到ZyyOvO的博客✨&#xff0c;一个关于探索技术的角落&#xff0c;记录学习的点滴&#x1f4d6;&#xff0c;分享实用的技巧&#x1f6e0;️&#xff0c;偶尔还有一些奇思妙想&#x1f4a1; 本文由ZyyOvO原创✍️&#xff0c;感谢支持❤️&#xff01;请尊重原创&#x1…

Qt warning LNK4042: 对象被多次指定;已忽略多余的指定

一、常规原因&#xff1a; pro或pri 文件中源文件被多次包含 解决&#xff1a;删除变量 SOURCES 和 HEADERS 中重复条目 二、误用 对于某些pri库可以使用如下代码简写包含 INCLUDEPATH $$PWDHEADERS $$PWD/*.hSOURCES $$PWD/*.cpp但是假如该目录下只有头文件&#xff0c;没…

Visual Studio Code 无法打开源文件解决方法

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux &#x1f525; 系列专栏&#xff1a;C从入门到精通 目录 一&#xff1a;&#x1f525; 突发状况 二&#xff1a;&#x1f525; 共勉 一&#xff1a;&#x1f525; 突发状况 &#x1f42c;…

js文字两端对齐

目录 一、问题 二、原因及解决方法 三、总结 一、问题 1.text-align: justify; 不就可以了吗&#xff1f;但是实际测试无效 二、原因及解决方法 1.原因&#xff1a;text-align只对非最后一行文字有效。只有一行文字时&#xff0c;text-align无效&#xff0c;要用text-alig…

LeetCode算法题(Go语言实现)_20

题目 给你两个下标从 0 开始的整数数组 nums1 和 nums2 &#xff0c;请你返回一个长度为 2 的列表 answer &#xff0c;其中&#xff1a; answer[0] 是 nums1 中所有 不 存在于 nums2 中的 不同 整数组成的列表。 answer[1] 是 nums2 中所有 不 存在于 nums1 中的 不同 整数组成…

每天认识一个设计模式-桥接模式:在抽象与实现的平行宇宙架起彩虹桥

一、前言&#xff1a;虚拟机桥接的启示 使用过VMware或者Docker的同学们应该都接触过网络桥接&#xff0c;在虚拟机网络配置里&#xff0c;桥接模式是常用的网络连接方式。选择桥接模式时&#xff0c;虚拟机会通过虚拟交换机与物理网卡相连&#xff0c;获取同网段 IP 地址&…

java笔记02

运算符 1.隐式转换和强制转换 类型转换的分类 1.隐式转换&#xff1a; 取值范围小的数值 转换为 取值范围大的数值 2.强制转换&#xff1a; 取值范围大的数值 转换为 取值范围小的数值隐式转换的两种提升规则 取值范围小的&#xff0c;和取值范围大的进行运算&#xff0c;小的…

Redis-07.Redis常用命令-集合操作命令

一.集合操作命令 SADD key member1 [member2]&#xff1a; sadd set1 a b c d sadd set1 a 0表示没有添加成功&#xff0c;因为集合中已经有了这个元素了&#xff0c;因此无法重复添加。 SMEMBERS key: smembers set1 SCARD key&#xff1a; scard set1 SADD key member1 …

李飞飞、吴佳俊团队新作:FlowMo如何以零卷积、零对抗损失实现ImageNet重构新巅峰

目录 一、摘要 二、引言 三、相关工作 四、方法 基于扩散先前的离散标记化器利用广告 架构 阶段 1A&#xff1a;模式匹配预训练 阶段 1B&#xff1a;模式搜索后训练 采样 第二阶段&#xff1a;潜在生成建模 五、Coovally AI模型训练与应用平台 六、实验 主要结果 …