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) 激发了网络安全行业的想象力,有可能彻底改变安全和 IT 团队处理网络危机、漏洞和勒索软件攻击的方式。 然而,对人工智能的能力和局限性的现实理解至关重要,并且存在许多挑战阻碍人工智能对网络安全产生直接的变革性影响。 在…...
BC99 序列中整数去重
描述 输入n个整数的序列,要求对这个序列进行去重操作。所谓去重,是指对这个序列中每个重复出现的整数,只保留该数第一次出现的位置,删除其余位置。 输入描述 输入包含两行,第一行包含一个正整数n(1 ≤ n…...
[PyTorch][chapter 52][迁移学习]
前言: 迁移学习(Transfer Learning)是一种机器学习方法,它通过将一个领域中的知识和经验迁移到另一个相关领域中,来加速和改进新领域的学习和解决问题的能力。 这里面主要结合前面ResNet18 例子,详细讲解一…...
Ceph如何操作底层对象数据
1.基本原理介绍 1.1 ceph中的对象(object) 在Ceph存储中,一切数据最终都会以对象(Object)的形式存储在硬盘(OSD)上,每个的Object默认大小为4M。 通过rados命令,可以查看一个存储池中的所有object信息,例如…...
sklearn机器学习库(二)sklearn中的随机森林
sklearn机器学习库(二)sklearn中的随机森林 集成算法会考虑多个评估器的建模结果,汇总之后得到一个综合的结果,以此来获取比单个模型更好的回归或分类表现。 多个模型集成成为的模型叫做集成评估器(ensemble estimator)…...
FlutterBoost 实现Flutter页面内嵌iOS view
在使用Flutter混合开发中会遇到一些原生比Flutter优秀的控件,不想使用Flutter的控件,想在Flutter中使用原生控件。这时就会用到 Flutter页面中内嵌 原生view,这里简单介绍一个 内嵌 iOS 的view。 注:这里使用了 FlutterBoost。网…...
走嵌入式还是纯软件?学长告诉你怎么选
最近有不少理工科的本科生问我,未来是走嵌入式还是纯软件好,究竟什么样的同学适合学习嵌入式呢?在这里我整合一下给他们的回答,根据自己的经验提供一些建议。 嵌入式领域也可以分为单片机方向、Linux方向和安卓方向。如果你的专业…...
【云计算原理及实战】初识云计算
该学习笔记取自《云计算原理及实战》一书,关于具体描述可以查阅原本书籍。 云计算被视为“革命性的计算模型”,因为它通过互联网自由流通使超级计算能力成为可能。 2006年8月,在圣何塞举办的SES(捜索引擎战略)大会上&a…...
Open3D (C++) 基于拟合高差的点云地面点提取
目录 一、算法原理1、原理概述2、参考文献二、代码实现三、结果展示1、原始点云2、提取结果四、相关链接系列文章(连载中。。。): Open3D (C++) 基于高程的点云地面点提取Open3D (C++) 基于拟合平面的点云地面点提取Open3D (C++) 基于拟合高差的点云地面点提取</...
认识Transformer:入门知识
视频链接: 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(HyperText Transfer Protocol,超文本传输协议)服务器端,即 Web 服务器端。 理解 Web 服务器端: web服务器端就是要基于 HTTP 协议,将网页对…...
【AI】文心一言的使用
一、获得内测资格: 1、点击网页链接申请:https://yiyan.baidu.com/ 2、点击加入体验,等待通过 二、获得AI伙伴内测名额 1、收到短信通知,点击链接 网页Link:https://chat.baidu.com/page/launch.html?fa&sourc…...
CSAPP Lab2:Bomb Lab
说明 6关卡,每个关卡需要输入相应的内容,通过逆向工程来获取对应关卡的通过条件 准备工作 环境 需要用到gdb调试器 apt-get install gdb系统: Ubuntu 22.04 本实验会用到的gdb调试器的指令如下 r或者 run或者run filename 运行程序,run filename就…...
Java中使用流将两个集合根据某个字段进行过滤去重?
Java中使用流将两个集合根据某个字段进行过滤去重? 在Java中,您可以使用流(Stream)来过滤和去重两个集合。下面是一个示例代码,展示如何根据对象的某个字段进行过滤和去重操作: import java.util.ArrayList; import java.util.List; impor…...
自动驾驶HMI产品技术方案
版本变更 序号 日期 变更内容 编制人 审核人 文档版本 1 2 1....
Git判断本地是否最新
场景需求 需要判断是否有新内容更新,确定有更新之后执行pull操作,然后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. 变量命名规范 弱类型语言(动态类型语言),定义变量的时候,不需要类型修饰 而且,变量类型可以随时改变每行代码结束的时候,要不要分号都可以变量名 由数字,字母下划线组成,不能以数字开头,也不…...
【Redis】什么是缓存穿透,如何预防缓存穿透?
【Redis】什么是缓存穿透,如何预防缓存穿透? 缓存穿透是指查询一个一定不存在的数据,由于缓存中不存在,这时会去数据库查询查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,这…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
