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

Spring AOP实现切入增强的两种方式(execution+annotation)-Demo

pom文件依赖

<!-- AOP切面编程启动环境依赖组 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

1、通过execution表达式实现切入增强

package com.xch.aop_execution.advicetype;import org.springframework.stereotype.Component;/*** 计算业务实现类** @author XuChenghe* @date 2023/8/19 17:43*/
@Component
public class Count {/*** 正常计算方法** @param num1* @param num2* @return*/public Integer normal(Integer num1, Integer num2) {System.out.println("-----执行正常计算方法的逻辑(开始)-----");int x = 1 / 1;System.out.println("-----执行正常计算方法的逻辑(结束)-----");return num1 + num2;}/*** 异常计算方法** @param num1* @param num2* @return*/public Integer abnormal(Integer num1, Integer num2) {System.out.println("-----执行异常计算方法的逻辑(开始)-----");int x = 1 / 0;System.out.println("-----执行异常计算方法的逻辑(结束)-----");return num1 - num2;}}
package com.xch.aop_execution.advicetype;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;import java.util.Arrays;/*** 计算业务的切面类:测试通知类型* -其中,后置通知/返回通知 和 最终通知的执行顺序,会根据Spring的版本而异** @author XuChenghe* @date 2023/8/19 17:41*/
@Aspect // 声明该类的作用:切面类
@Component // 等价于@Configuration:交由Spring的IOC容器管理
public class CountAspect {/*** 定义公共切入点* execution表达式配置规则:* -execution([修饰符] 返回类型 方法全限定名称(参数) [异常])* -其中修饰符和异常可选* -参数..代表任意入参* -*代表任意返回类型或任意方法名* -*xxx/xxx*代表以xxx结尾或开头的任意方法名* -xxx.*代表xxx类下的所有方法或xxx包下所有类的所有方法* -xxx..*代表xxx包下所有包或类的所有方法*/@Pointcut("execution(* com.xch.aop_execution.advicetype.Count.*(..))")public void myPointcut() {// 公共切入点}/*** 前置通知** @param joinPoint 连接点:当前切入方法的信息*/@Before("myPointcut()")public void before(JoinPoint joinPoint) {System.out.println("=====前置通知(开始):执行安全检查逻辑=====");// 前置通知,可以拿到方法名称+方法入参String name = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("name = " + name);System.out.println("args = " + Arrays.toString(args));System.out.println("=====前置通知(结束):执行安全检查逻辑=====");}/*** 后置通知/返回通知* 只有目标方法中没有抛出异常,即正常执行返回结果后,才进入该通知** @param joinPoint 连接点:当前切入方法的信息* @param result    方法执行的返回结果*/@AfterReturning(pointcut = "myPointcut()", returning = "result")public void afterReturning(JoinPoint joinPoint, Object result) {System.out.println("=====后置通知/返回通知(开始):记录日志=====");// 后置通知/返回通知,可以拿到方法名称+方法入参+方法返回值String name = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("name = " + name);System.out.println("args = " + Arrays.toString(args));System.out.println("result = " + result);System.out.println("=====后置通知/返回通知(结束):记录日志=====");}/*** 最终通知* 不管目标方法中有没有抛出异常,都会进入该通知** @param joinPoint 连接点:当前切入方法的信息*/@After("myPointcut()")public void after(JoinPoint joinPoint) {System.out.println("=====最终通知(开始):释放资源=====");// 最终通知,可以拿到方法名称+方法入参String name = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("name = " + name);System.out.println("args = " + Arrays.toString(args));System.out.println("=====最终通知(结束):释放资源=====");}/*** 环绕通知* 该通知等价于其余四种通知的大集合* 执行了被切入的方法代码,改变了原执行路径,需返回执行结果** @param pjp 连接点:当前切入方法的信息* @return 方法执行的返回结果* @throws Throwable 方法执行时抛出的异常*/@Around("myPointcut()")public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("=====环绕通知(开始):手动开启事务=====");// 环绕通知,可以拿到方法名称+方法入参+方法返回值String name = pjp.getSignature().getName();Object[] args = pjp.getArgs();Object proceed = pjp.proceed();System.out.println("name = " + name);System.out.println("args = " + Arrays.toString(args));System.out.println("proceed = " + proceed);System.out.println("=====环绕通知(结束):手动提交事务=====");return proceed;}/*** 抛出异常后通知* 不能在Around环绕通知中捕获异常,否则不会给Spring AOP处理进入该通知** @param joinPoint 连接点:当前切入方法的信息* @param exception 方法执行时抛出的异常*/@AfterThrowing(pointcut = "myPointcut()", throwing = "exception")public void afterThrowing(JoinPoint joinPoint, Exception exception) {System.out.println("=====抛出异常后通知(开始):手动回滚事务=====");// 抛出异常后通知,可以拿到方法名称+方法入参+抛出的异常String name = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("name = " + name);System.out.println("args = " + Arrays.toString(args));exception.printStackTrace();System.out.println("=====抛出异常后通知(结束):手动回滚事务=====");}}
package com.xch.aop_execution.advicetype;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;/*** 计算业务测试类** @author XuChenghe* @date 2023/8/19 18:17*/
@SpringBootTest
public class CountTest {@Autowiredprivate Count count;@Testpublic void test() {count.normal(3, 8);System.out.println();count.abnormal(8, 3);}}

2、通过annotation注解实现切入增强

package com.xch.aop_annotation.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** 用户信息实体类** @author XuChenghe* @date 2023/8/19 12:37*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {/*** 用户ID*/private Integer id;/*** 用户名称*/private String name;}
package com.xch.aop_annotation.controller;import com.xch.aop_annotation.annotation.LogAnnotation;
import com.xch.aop_annotation.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Arrays;
import java.util.List;/*** 用户信息管理接口层实现类** @author XuChenghe* @date 2023/8/19 12:35*/
@RestController
@RequestMapping("/user")
public class UserController {/*** 获取所有用户信息** @return*/@GetMapping("/getUserList")public List<User> getUserList() {// 模拟业务的数据库操作return Arrays.asList(new User(1, "Alice"),new User(2, "Bob"),new User(3, "Lucy"));}/*** 通过用户ID获取用户信息** @param id* @return*/@GetMapping("/getUserById/{id}")public User getUserById(@PathVariable("id") Integer id) {// 模拟业务的数据库操作return new User(1, "Alice");}/*** 通过用户名称获取用户信息** @param name* @return*/@GetMapping("/getUserByName/{name}")public User getUserByName(@PathVariable("name") String name) {// 模拟业务的数据库操作return new User(2, "Bob");}/*** 保存用户信息** @return*/@GetMapping("/saveUser")@LogAnnotation("保存用户信息")public String saveUser() {// 模拟业务的数据库操作return "添加用户信息成功!";}/*** 编辑用户信息** @return*/@GetMapping("/editUser")@LogAnnotation("编辑用户信息")public String editUser() {// 模拟业务的数据库操作return "编辑用户信息成功!";}/*** 通过用户ID删除用户信息** @param id* @return*/@GetMapping("/deleteUserById/{id}")@LogAnnotation("通过用户ID删除用户信息")public String deleteUserById(@PathVariable("id") Integer id) {// 模拟业务的数据库操作return "通过用户ID删除用户信息成功!";}/*** 通过用户名称删除用户信息** @param name* @return*/@GetMapping("/deleteUserByName/{name}")@LogAnnotation("通过用户名称删除用户信息")public String deleteUserByName(@PathVariable("name") String name) {// 模拟业务的数据库操作return "通过用户名称删除用户信息成功!";}}
package com.xch.aop_annotation.annotation;import java.lang.annotation.*;/*** 记录写操作方法日志的注解** @author XuChenghe* @date 2023/8/19 12:57*/
@Target(ElementType.METHOD) // 声明该注解作用的地方:方法
@Retention(RetentionPolicy.RUNTIME) // 声明该注解作用的时间:运行时
@Documented // 以上三个都是元注解:描述注解的注解
public @interface LogAnnotation {/*** 方法的作用描述*/String value() default "暂无作用描述(默认)";}
package com.xch.aop_annotation.aspect;import com.xch.aop_annotation.annotation.LogAnnotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.util.Arrays;/*** 记录写操作方法日志的的切面类** @author XuChenghe* @date 2023/8/19 13:06*/
@Aspect // 声明该类的作用:切面类
@Component // 等价于@Configuration:交由Spring的IOC容器管理
public class LogAspect {/*** 定义公共切入点*/@Pointcut("@annotation(com.xch.aop_annotation.annotation.LogAnnotation)")public void logPointCut() {// 公共切入点}/*** 切面的执行方法(环绕通知):记录日志操作的代码** @param pjp 连接点:当前切入方法的信息* @return 方法执行的返回结果*/@Around("logPointCut()")public Object around(ProceedingJoinPoint pjp) throws Throwable {// 模拟业务的记录日志到数据库操作// 当前切入的方法名称String name = pjp.getSignature().getName();// 当前切入的方法返回值(执行了被切入的方法代码,改变了原执行路径,需返回执行结果)Object proceed = pjp.proceed();// 当前切入的方法入参Object[] args = pjp.getArgs();// 获取注解的属性内容// 1.通过反射反向获取方法MethodSignature signature = (MethodSignature) pjp.getSignature();Method method = signature.getMethod();// 2.通过反射反向获取注解LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);if (logAnnotation != null) {String value = logAnnotation.value();System.out.println("========================================");System.out.println("name = " + name);System.out.println("proceed = " + proceed);System.out.println("args = " + Arrays.toString(args));System.out.println("value = " + value);System.out.println("========================================");}return proceed;}}

相关文章:

Spring AOP实现切入增强的两种方式(execution+annotation)-Demo

pom文件依赖 <!-- AOP切面编程启动环境依赖组 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId> </dependency> 1、通过execution表达式实现切入增强 package com…...

人工智能在网络安全中的作用:当前的局限性和未来的可能性

人工智能 (AI) 激发了网络安全行业的想象力&#xff0c;有可能彻底改变安全和 IT 团队处理网络危机、漏洞和勒索软件攻击的方式。 然而&#xff0c;对人工智能的能力和局限性的现实理解至关重要&#xff0c;并且存在许多挑战阻碍人工智能对网络安全产生直接的变革性影响。 在…...

BC99 序列中整数去重

描述 输入n个整数的序列&#xff0c;要求对这个序列进行去重操作。所谓去重&#xff0c;是指对这个序列中每个重复出现的整数&#xff0c;只保留该数第一次出现的位置&#xff0c;删除其余位置。 输入描述 输入包含两行&#xff0c;第一行包含一个正整数n&#xff08;1 ≤ n…...

[PyTorch][chapter 52][迁移学习]

前言&#xff1a; 迁移学习&#xff08;Transfer Learning&#xff09;是一种机器学习方法&#xff0c;它通过将一个领域中的知识和经验迁移到另一个相关领域中&#xff0c;来加速和改进新领域的学习和解决问题的能力。 这里面主要结合前面ResNet18 例子&#xff0c;详细讲解一…...

Ceph如何操作底层对象数据

1.基本原理介绍 1.1 ceph中的对象(object) 在Ceph存储中&#xff0c;一切数据最终都会以对象(Object)的形式存储在硬盘&#xff08;OSD&#xff09;上&#xff0c;每个的Object默认大小为4M。 通过rados命令&#xff0c;可以查看一个存储池中的所有object信息&#xff0c;例如…...

sklearn机器学习库(二)sklearn中的随机森林

sklearn机器学习库(二)sklearn中的随机森林 集成算法会考虑多个评估器的建模结果&#xff0c;汇总之后得到一个综合的结果&#xff0c;以此来获取比单个模型更好的回归或分类表现。 多个模型集成成为的模型叫做集成评估器&#xff08;ensemble estimator&#xff09;&#xf…...

FlutterBoost 实现Flutter页面内嵌iOS view

在使用Flutter混合开发中会遇到一些原生比Flutter优秀的控件&#xff0c;不想使用Flutter的控件&#xff0c;想在Flutter中使用原生控件。这时就会用到 Flutter页面中内嵌 原生view&#xff0c;这里简单介绍一个 内嵌 iOS 的view。 注&#xff1a;这里使用了 FlutterBoost。网…...

走嵌入式还是纯软件?学长告诉你怎么选

最近有不少理工科的本科生问我&#xff0c;未来是走嵌入式还是纯软件好&#xff0c;究竟什么样的同学适合学习嵌入式呢&#xff1f;在这里我整合一下给他们的回答&#xff0c;根据自己的经验提供一些建议。 嵌入式领域也可以分为单片机方向、Linux方向和安卓方向。如果你的专业…...

【云计算原理及实战】初识云计算

该学习笔记取自《云计算原理及实战》一书&#xff0c;关于具体描述可以查阅原本书籍。 云计算被视为“革命性的计算模型”&#xff0c;因为它通过互联网自由流通使超级计算能力成为可能。 2006年8月&#xff0c;在圣何塞举办的SES&#xff08;捜索引擎战略&#xff09;大会上&a…...

Open3D (C++) 基于拟合高差的点云地面点提取

目录 一、算法原理1、原理概述2、参考文献二、代码实现三、结果展示1、原始点云2、提取结果四、相关链接系列文章(连载中。。。): Open3D (C++) 基于高程的点云地面点提取Open3D (C++) 基于拟合平面的点云地面点提取Open3D (C++) 基于拟合高差的点云地面点提取</...

认识Transformer:入门知识

视频链接&#xff1a; https://www.youtube.com/watch?vugWDIIOHtPA&listPLJV_el3uVTsOK_ZK5L0Iv_EQoL1JefRL4&index60 文章目录 Self-Attention layerMulti-head self-attentionPositional encodingSeq2Seq with AttentionTransformerUniversal Transformer Seq2Seq …...

《TCP IP网络编程》第二十四章

第 24 章 制作 HTTP 服务器端 24.1 HTTP 概要 本章将编写 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;服务器端&#xff0c;即 Web 服务器端。 理解 Web 服务器端&#xff1a; web服务器端就是要基于 HTTP 协议&#xff0c;将网页对…...

【AI】文心一言的使用

一、获得内测资格&#xff1a; 1、点击网页链接申请&#xff1a;https://yiyan.baidu.com/ 2、点击加入体验&#xff0c;等待通过 二、获得AI伙伴内测名额 1、收到短信通知&#xff0c;点击链接 网页Link&#xff1a;https://chat.baidu.com/page/launch.html?fa&sourc…...

CSAPP Lab2:Bomb Lab

说明 6关卡&#xff0c;每个关卡需要输入相应的内容&#xff0c;通过逆向工程来获取对应关卡的通过条件 准备工作 环境 需要用到gdb调试器 apt-get install gdb系统: Ubuntu 22.04 本实验会用到的gdb调试器的指令如下 r或者 run或者run filename 运行程序,run filename就…...

Java中使用流将两个集合根据某个字段进行过滤去重?

Java中使用流将两个集合根据某个字段进行过滤去重? 在Java中&#xff0c;您可以使用流(Stream)来过滤和去重两个集合。下面是一个示例代码&#xff0c;展示如何根据对象的某个字段进行过滤和去重操作&#xff1a; import java.util.ArrayList; import java.util.List; impor…...

自动驾驶HMI产品技术方案

版本变更 序号 日期 变更内容 编制人 审核人 文档版本 1 2 1....

Git判断本地是否最新

场景需求 需要判断是否有新内容更新,确定有更新之后执行pull操作&#xff0c;然后pull成功之后再将新内容进行复制到其他地方 pgit log -1 --prettyformat:"%H" HEAD -- . "origin/HEAD" rgit rev-parse origin/HEAD if [[ $p $r ]];thenecho "Is La…...

Spring 整合RabbitMQ,笔记整理

1.创建生产者工程 spring-rabbitmq-producer 2.pom.xml添加依赖 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.7.RELEASE</version></dep…...

Lua 语言笔记(一)

1. 变量命名规范 弱类型语言(动态类型语言)&#xff0c;定义变量的时候&#xff0c;不需要类型修饰 而且&#xff0c;变量类型可以随时改变每行代码结束的时候&#xff0c;要不要分号都可以变量名 由数字&#xff0c;字母下划线组成&#xff0c;不能以数字开头&#xff0c;也不…...

【Redis】什么是缓存穿透,如何预防缓存穿透?

【Redis】什么是缓存穿透&#xff0c;如何预防缓存穿透&#xff1f; 缓存穿透是指查询一个一定不存在的数据&#xff0c;由于缓存中不存在&#xff0c;这时会去数据库查询查不到数据则不写入缓存&#xff0c;这将导致这个不存在的数据每次请求都要到数据库去查询&#xff0c;这…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

Modbus RTU与Modbus TCP详解指南

目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...

快速排序算法改进:随机快排-荷兰国旗划分详解

随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”

非常好&#xff0c;我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题&#xff0c;统一使用 二重复合函数&#xff1a; z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y))​ 来全面说明。我们会展示其全微分形式&#xff08;偏导…...