当前位置: 首页 > 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;这…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...