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

SpringAOP 面向切面编程

** Spring有两大核心特性:IOC(控制反转) 和 AOP(面向切面编程),但是 相比IOC在日常工作中的广泛应用,AOP却常常做了冷板凳,下面我从工作中的场景为大家打开AOP面向切面编程的大门。**

什么是AOP?

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

下面用一张图理解一下AOP:

在这里插入图片描述

可以看到,通过AOP技术,我们可以通过将业务中的通用部分抽取出来,并对业务进行加强,而我们只需要关心具体的业务逻辑即可。

下面是AOP相关的一些概念:

  • Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。

  • Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。

  • Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。

  • Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。

  • Target(目标对象):织入 Advice 的目标对象.。

  • Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

那么在工作中,AOP具体怎么用呢?

场景1: 接口限流

背景:假设我们需要对一些接口进行限流,要求同一个用户指定时间内不可重复请求。

代码实现:

  1. 首先在类上面添加@Aspect标识这是一个切面类 并添加@Component注解让其被Spring发现

    @Slf4j
    @Aspect
    @Component
    public class RateLimitingAspect {
    
  2. 创建切面方法,并定义增强类型及切入点

    @Around("@annotation(com.beansmile.common.config.RateLimiting)")public Object rateLimiting(ProceedingJoinPoint pjp) throws Throwable {
    

    其中@Around代表增强类型为环绕增强、除此之外还有:before(执行前) after(执行后),注解的内容是设置的切入点,这里设置的为添加@RateLimiting注解的地方,此处也可以通过表达式设置为 xxx包下的类、xxx类下方法等等

  3. 创建自定义注解: RateLimiting

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface RateLimiting {/*** 间隔时间,单位秒*/int limitInSeconds() default 2;/*** 返回信息*/String returnMsg() default "您的请求太快了,请稍后提交!";
    }
    
  4. 具体逻辑代码

        @Around("@annotation(com.beansmile.common.config.RateLimiting)")public Object rateLimiting(ProceedingJoinPoint pjp) throws Throwable {String method = pjp.getSignature().toShortString();// lockKey = userId:xxxController.xxxMethod()String lockKey = AuthUtil.getUserId() + ":" + method;MethodSignature methodSignature = (MethodSignature) pjp.getSignature();Method signatureMethod = methodSignature.getMethod();// 拿到注解内容RateLimiting rateLimitingAnnotation = signatureMethod.getAnnotation(RateLimiting.class);String returnMsg = rateLimitingAnnotation.returnMsg();int limitInSeconds = rateLimitingAnnotation.limitInSeconds();Boolean lock = redisTemplate.opsForValue().setIfAbsent(method, 1, limitInSeconds, TimeUnit.SECONDS);if (BooleanUtils.isTrue(lock)) {// 放行return pjp.proceed();} else {log.info("请求限流,lockKey:{},间隔时间:{}", lockKey, limitInSeconds);throw new ServiceException(returnMsg);}}
    

上述代码中,我们以 userId + 类名称 + 方法名称 作为唯一标识,通过redis锁的方式进行限流。

测试代码:  这里我们设置了请求间隔为1秒
    @RequestMapping(value = "/test", method = RequestMethod.GET)@RateLimiting(limitInSeconds = 1)public Result<?> test() {// 具体业务逻辑// xxxxxxxxxxxxxreturn Result.OK("操作成功!");}

正常请求:

在这里插入图片描述

快速请求:

在这里插入图片描述

可以看到,我们通过使用AOP的方式实现了 接口限流的逻辑,并且没有修改任何业务逻辑。

场景2: 全局异常捕获

背景:在程序运行时不可避免的会出现一些异常, 如NullPointerException空指针、ArrayIndexOutOfBoundsException数组下标越界等, 这些异常直接抛到前端页面会导致用户体验不好,过多的try/catch捕捉又会导致代码冗余。

代码实现:

  1. 定义切入点
	@Pointcut("execution(public * com.beansmile.modules..*.*Controller.*(..)))")public void exceptionPointcut() {}

这里定义的切入点为 com.beansmile.modules包下 所有控制器下的方法。

  1. 创建异常枚举类
@Getter
@AllArgsConstructor
public enum ExceptionEnum {/*** NullPointerException*/NULL_POINTER(10001, NullPointerException.class, "空指针异常"),/*** ArrayIndexOutOfBoundsException*/ARRAY_INDEX_OUT_OF_BOUND(10002, ArrayIndexOutOfBoundsException.class, "数组下标越界"),/*** IOException*/IO(10003, IOException.class, "输入输出异常");final int code;final Class<?> clazz;final String name;public static ExceptionEnum getEnumByClazz(Class<?> clazz) {for (ExceptionEnum exceptionEnum : values()) {if (clazz.isAssignableFrom(exceptionEnum.clazz)) {return exceptionEnum;}}return null;}
}
  1. 具体逻辑代码
	@Around("exceptionPointcut()")public Object exceptionHandling(ProceedingJoinPoint pjp) throws Throwable {try {return pjp.proceed();} catch (Exception e) {// 通过枚举类获取异常信息ExceptionEnum exceptionEnum = ExceptionEnum.getEnumByClazz(e.getClass());if (null == exceptionEnum) throw e;// 打印异常信息printExceptionInfo(pjp, e);// 抛出自定义异常,并携带错误码用于快速排查。throw new JeecgBootException("网络开小差了,请稍后重试或联系客服![" + exceptionEnum.getCode() + "]");}}private void printExceptionInfo(ProceedingJoinPoint pjp, Exception e) {String methodName = pjp.getSignature().getName();String className = pjp.getTarget().getClass().getSimpleName();log.error("printExceptionInfo_类名:{},方法名:{},异常信息:{}", className, methodName, e.toString());e.printStackTrace();}

上述代码中,通过对异常时进行切入,对异常做了统一抛出和打印日志。

测试代码

    @RequestMapping(value = "/test", method = RequestMethod.GET)public Result<?> test() {// 模拟空指针异常String str = null;str.length();return Result.OK("操作成功!");}

请求接口进行测试:符合预期,统一错误返回,并携带错误码

在这里插入图片描述

查看后端日志: 保留了原始错误信息,并快速记录了错误的发生源头。

printExceptionInfo_类名:ApprovalFlowController,方法名:test,异常信息:java.lang.NullPointerException
java.lang.NullPointerException

相关文章:

SpringAOP 面向切面编程

** Spring有两大核心特性&#xff1a;IOC(控制反转) 和 AOP(面向切面编程)&#xff0c;但是 相比IOC在日常工作中的广泛应用&#xff0c;AOP却常常做了冷板凳&#xff0c;下面我从工作中的场景为大家打开AOP面向切面编程的大门。** 什么是AOP? 在软件业&#xff0c;AOP为Asp…...

灵办AI助手Chrome插件全面评测:PC Web端的智能办公利器

探索灵办AI助手在Mac OS上的高效表现&#xff0c;支持多款主流浏览器&#xff0c;助你轻松应对办公挑战 文章目录 探索灵办AI助手在Mac OS上的高效表现&#xff0c;支持多款主流浏览器&#xff0c;助你轻松应对办公挑战摘要引言开发环境介绍核心功能评测1. 网页翻译与双语对照 …...

Rancher 使用 Minio 备份 Longhorn 数据卷

0. 概述 Longhorn 支持备份到 NFS 或者 S3, 而 MinIO 就是符合 S3 的对象存储服务。通过 docker 部署 minio 服务&#xff0c;然后在 Longhorn UI 中配置备份服务即可。 1. MinIO 部署 1.1 创建备份目录 mkdir -p /home/longhorn-backup/minio/data mkdir -p /home/longhor…...

useRequest

用法 默认用法 第一参数是异步函数&#xff08;接口&#xff09;&#xff0c;在组件初次加载时&#xff0c;会自动触发该函数执行。 const { data, error, loading } useRequest(getUsername);第二个参数&#xff0c;是一个配置选项&#xff08;一个对象&#xff09; 详解…...

python动画:manim实现多面体的创建

一&#xff0c;介绍 内容 多面体&#xff08;discusses polyhedra&#xff09;&#xff0c;主要集中在一种称为多面体的几何形状类别&#xff0c;并突出介绍了五种柏拉图体&#xff08;Platonic solids&#xff09;&#xff0c;这些是具有特殊性质的多面体类型。 多面体 定义…...

数值计算引擎:搭建远程容器开发环境

Build VS Code Remote Docker Development Environment 大型CAE软件开发技术栈通常依赖多个第三方库&#xff0c;因此从零开始配置开发、编译、运行等环境通常较为繁琐。但随着公司的发展壮大&#xff0c;却经常需要为新加入的成员配备相应的开发环境&#xff1b;另外&#xf…...

二叉搜索树(Binary Search Tree)

1.二叉搜索树概念 二叉搜索树又称二叉排序树、二叉查找树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 1. 非空左子树的所有键值小于其根节点的键值 2. 非空右子树的所有键值大于其根节点的键值 3. 左右子树也分别为二叉搜索树 二叉搜索树一般不支持…...

Yii2框架的初始化及执行流程

当 Yii2 框架执行 index.php 入口脚本后&#xff0c;内部执行逻辑和顺序可以概括如下&#xff1a; 1、加载相关配置文件和关键组件&#xff1a; 加载 Composer 自动加载器&#xff1a; require DIR . ‘/…/vendor/autoload.php’; 加载 Yii 框架文件&#xff1a; require D…...

2024.1-2024.2pycharm无法打开terminal命令行

2024版的idea或pycharm打开terminal时会发生如下问题&#xff1a; Cannot open Windows PowerShell Failed to start [C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe,或 Cannot open Command Prompt Failed to start [C:\Windows\system32\cmd.exe] 需要点击标…...

50ETF期权移仓是什么?50ETF期权移仓要注意什么?

今天带你了解50ETF期权移仓是什么&#xff1f;50ETF期权移仓要注意什么&#xff1f;当前火热的期权交易市场&#xff0c;“移仓”同样是一门非常重要的技术。上证50ETF期权投资的过程中&#xff0c;我们可以进行一定的移仓操作的&#xff0c;如果移仓操作得好&#xff0c;可以很…...

软件工程概述(上)

1、软件的概念、特点和分类 要了解软件工程&#xff0c;首先让我们重新认识一下软件。如今可以说是一个软件定义一切的时代&#xff0c;虽然人工智能发展的如火如荼&#xff0c;但究其本质&#xff0c;核心还是软件。那么&#xff0c;如何给软件下一个定义呢&#xff1f;软件又…...

阿里云ubuntu系统安装mysql8.0

一、安装mysql8.0 1.已安装其他版本的mysql&#xff0c;需要删除 若没有不需要此操作 1 #卸载MySQL5.7版本 2 apt remove -y mysql-client5.7* mysql-community-server5.7* 4 # 卸载5.7的仓库信息 5 dpkg-l | grep mysql | awk iprint $2} | xargs dpkg -P2.更新仓库 apt u…...

自己搭建远程桌面服务器-RustDesk 极简版

linux搭建RustDesk保姆间教程_rustdesk linux-CSDN博客https://blog.csdn.net/yzs2022/article/details/135136491 背景 在某公司工作&#xff0c;向日葵等远程办公软件均已屏蔽&#xff0c;无法使用&#xff08;也没有明文规定不允许使用远程控制软件&#xff09;&#xff0c…...

数字资产是什么?怎么产生?怎么增长?

数字资产是什么&#xff1f; 数字资产是指企业或个人拥有或控制的&#xff0c;以电子数据形式存在的&#xff0c;在日常活动中持有以备出售或处于生产过程中的非货币性资产。它涵盖了广泛的范围&#xff0c;包括但不限于数字货币、数字证券、数字艺术品、虚拟土地等。这些资产…...

Centos7升级gitlab(17)

在 CentOS 7 中将 GitLab 从版本 17.1.1 升级到 17.2.2&#xff0c;涉及以下步骤。请务必在升级前备份数据&#xff0c;以防止升级过程中出现问题导致数据丢失。 升级步骤 1. 备份 GitLab 数据 在升级之前&#xff0c;确保已经备份了 GitLab 的数据&#xff0c;包括数据库、…...

Zookeeper详解以及常见的高可用关联组件

一、ZooKeeper 详解 Apache ZooKeeper 是一个开源的分布式协调服务&#xff0c;用于分布式应用程序之间的协调和管理。ZooKeeper 提供了一个高效、可靠的服务来帮助管理分布式系统中的共享配置信息、命名、同步和组服务等。 二、主要特性 1. 高可用性 ZooKeeper 集群通过选…...

Docker Containerd初体验

Docker Containerd概述 ​ Containerd是一个开源的容器运行时&#xff0c;它提供了一种标准化的方式来管理容器的生命周期。该项目最初是由Docker开发团队创建的&#xff0c;并在后来成为了一个独立的项目&#xff0c;被纳入了Cloud Native Computing Foundation&#xff08;C…...

开始使用 AWS SAM CLI

了解如何使用 AWS SAM CLI 在本地调试 lambda 函数 欢迎来到雲闪世界。我们将学习 AWS SAM CLI 的概念。SAM 是无服务器 应用程序 模型的缩写&#xff0c;是 Amazon Web Services 提供的一个框架&#xff0c;可以利用它在本地机器上构建应用程序并将其直接部署到 AWS Lambdas。…...

RK3588 RTL8125BG调试

RTL8125B是一款PCIE转RJ45的网卡控制器芯片&#xff0c;在底层调试时只需配置PCIE即可 diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nvr-demo.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-nvr-demo.dtsi index 798359eaf061..d8a7a43cdfa0 100755 --- a/arch/arm64/bo…...

Python自省(机制与函数)

Python 自省&#xff08;Introspection&#xff09;是一种强大的特性&#xff0c;它允许程序在运行时检查对象的类型、属性以及它们如何相互关联。这种能力让 Python 非常适合于快速开发、调试以及编写需要高度动态交互的代码。Python 的自省机制主要通过内置的函数和类型来实现…...

终极AMD Ryzen调试教程:3步掌握专业级硬件调优工具SMUDebugTool

终极AMD Ryzen调试教程&#xff1a;3步掌握专业级硬件调优工具SMUDebugTool 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: h…...

中文分词与词频统计全流程实战 | 全网独家复现,Python零基础落地篇 引入jieba分词优化+多策略词频统计,助力文本挖掘、舆情分析、学术研究高效落地

目录 一、核心前言(明确价值,避开踩坑) 1.1 实战意义 1.2 技术选型说明 1.3 前置准备(零基础必看) 二、核心原理(极简理解,无需深入) 2.1 中文分词原理 2.2 词频统计原理 三、全流程代码实现(零基础可复制,全程注释) 3.1 工程化目录结构(必看,避免路径错…...

告别‘薛定谔的网卡’:在Ubuntu 20.04上为RTL8168网卡手动编译驱动并配置开机自启的完整记录

深度解析&#xff1a;Ubuntu 20.04下RTL8168网卡驱动的编译与持久化加载实战当你盯着Ubuntu系统托盘上那个时隐时现的网络图标&#xff0c;或是反复插拔网线却依然无法获得稳定的有线连接时&#xff0c;可能正遭遇着经典的RTL8168网卡驱动问题。这个被开发者戏称为"薛定谔…...

机器学习赋能微服务架构拆分:从图划分到智能决策的工程实践

1. 从单体巨石到微服务&#xff1a;为什么我们需要机器学习的“火眼金睛”在软件架构演进的漫长征途中&#xff0c;我们正经历一场深刻的范式转移。曾几何时&#xff0c;单体架构&#xff08;Monolithic Architecture&#xff09;因其开发简单、部署直接而大行其道&#xff0c;…...

XUnity.AutoTranslator:如何免费实现Unity游戏实时翻译的完整指南

XUnity.AutoTranslator&#xff1a;如何免费实现Unity游戏实时翻译的完整指南 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 在游戏的世界里&#xff0c;语言障碍常常成为玩家体验全球优秀作品的绊脚石。…...

FPGA在遥感机器学习中的优势与优化实践

1. FPGA在遥感机器学习中的核心优势解析 FPGA&#xff08;现场可编程门阵列&#xff09;在边缘计算场景中展现出独特的价值主张。与通用处理器不同&#xff0c;FPGA通过硬件级并行架构实现两个关键突破&#xff1a;首先是数据流驱动的计算模式&#xff0c;消除传统冯诺依曼架构…...

医学影像AI迁移学习:如何科学选择预训练数据集?

1. 项目概述在医学影像分析这个对精度和可靠性要求极高的领域&#xff0c;迁移学习已经成为解决数据稀缺问题的关键技术路径。其核心逻辑很直观&#xff1a;与其在有限的目标数据上从头训练一个复杂的深度学习模型&#xff0c;不如先在一个庞大的、通用的源数据集上“预训练”模…...

HTTPS抓包失败的七层根因与实战定位法

1. 为什么HTTPS抓包总在“看不见”的地方翻车&#xff1f;你刚配好Fiddler或Charles&#xff0c;证书也装了、代理也开了、手机Wi-Fi也指向了电脑IP&#xff0c;可一打开App——抓包窗口空空如也&#xff0c;连个DNS请求都不见&#xff1b;或者只看到一堆CONNECT隧道建立记录&a…...

Atomic Layout测试策略:单元测试与集成测试最佳实践

Atomic Layout测试策略&#xff1a;单元测试与集成测试最佳实践 【免费下载链接】atomic-layout Build declarative, responsive layouts in React using CSS Grid. 项目地址: https://gitcode.com/gh_mirrors/at/atomic-layout 在现代前端开发中&#xff0c;构建可靠的…...

保姆级教程:用阿里云镜像加速Unity Android依赖下载,搞定MAX+Admob集成

深度优化Unity安卓依赖下载&#xff1a;阿里云镜像加速MAX与AdMob集成实战国内Unity开发者在集成海外广告SDK时&#xff0c;最头疼的莫过于Gradle依赖下载缓慢甚至失败的问题。本文将手把手教你如何通过阿里云镜像仓库彻底解决这一痛点&#xff0c;同时串联Gradle版本管理、mai…...