Spring AOP 典型应用场景

AOP 典型应用场景

      • 1. 日志记录(Logging)
        • 代码实现
      • 2. 权限校验(Authentication)
        • 代码实现
      • 3. 性能监控(Performance Monitoring)
        • 代码实现
      • 4. 缓存处理(Caching)
        • 代码实现
      • 5. 重试机制(Retry)
        • 代码实现
      • 6. 事务管理(Transaction Management)
        • 代码实现
      • 7. 接口限流(Rate Limiting)
        • 代码实现
      • 总结表格

在这里插入图片描述

1. 日志记录(Logging)

场景:自动记录方法的入参、返回值、执行时间和异常信息。

代码实现

1. 自定义日志注解

// annotation/Loggable.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {String tag() default "DEFAULT";
}

2. 切面逻辑

// aop/LoggingAspect.java
@Aspect
@Component
public class LoggingAspect {private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);@Around("@annotation(loggable)")public Object logMethod(ProceedingJoinPoint pjp, Loggable loggable) throws Throwable {String methodName = pjp.getSignature().getName();String className = pjp.getTarget().getClass().getSimpleName();String tag = loggable.tag();// 记录方法开始logger.info("[{}] {}.{}() 入参: {}", tag, className, methodName, Arrays.toString(pjp.getArgs()));long startTime = System.currentTimeMillis();try {Object result = pjp.proceed();long duration = System.currentTimeMillis() - startTime;// 记录方法结束logger.info("[{}] {}.{}() 耗时: {}ms 返回: {}", tag, className, methodName, duration, result);return result;} catch (Exception e) {// 记录异常logger.error("[{}] {}.{}() 异常: {}", tag, className, methodName, e.getMessage(), e);throw e;}}
}

3. 业务类使用

// service/UserService.java
@Service
public class UserService {@Loggable(tag = "USER-SERVICE")public String getUserById(Long id) {return "User-" + id; // 模拟数据库查询}
}

4. 测试运行

// MainApp.java
public class MainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = context.getBean(UserService.class);userService.getUserById(123L);context.close();}
}

输出结果

[USER-SERVICE] UserService.getUserById() 入参: [123]
[USER-SERVICE] UserService.getUserById() 耗时: 2ms 返回: User-123

2. 权限校验(Authentication)

场景:验证用户是否具有访问特定方法的权限。

代码实现

1. 自定义权限注解

// annotation/RequireRole.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequireRole {String value() default "USER";
}

2. 切面逻辑

// aop/SecurityAspect.java
@Aspect
@Component
public class SecurityAspect {// 模拟当前用户角色private String currentUserRole = "ADMIN";@Before("@annotation(requireRole)")public void checkPermission(JoinPoint jp, RequireRole requireRole) {String requiredRole = requireRole.value();if (!requiredRole.equals(currentUserRole)) {throw new SecurityException("权限不足! 需要角色: " + requiredRole);}}
}

3. 业务类使用

// service/AdminService.java
@Service
public class AdminService {@RequireRole("ADMIN")public void deleteDatabase() {System.out.println("数据库已删除!"); // 危险操作}
}

4. 测试运行

public class MainApp {public static void main(String[] args) {try {AdminService adminService = context.getBean(AdminService.class);adminService.deleteDatabase();} catch (Exception e) {System.out.println("错误: " + e.getMessage());}}
}

输出结果

数据库已删除!  // 如果currentUserRole="ADMIN"
错误: 权限不足! 需要角色: ADMIN  // 如果currentUserRole="USER"

3. 性能监控(Performance Monitoring)

场景:统计方法执行耗时,用于性能分析。

代码实现

1. 切面逻辑

// aop/PerformanceAspect.java
@Aspect
@Component
public class PerformanceAspect {@Around("execution(* com.example.service.*.*(..))")public Object monitorPerformance(ProceedingJoinPoint pjp) throws Throwable {long start = System.currentTimeMillis();Object result = pjp.proceed();long duration = System.currentTimeMillis() - start;String methodName = pjp.getSignature().getName();System.out.println("方法 " + methodName + " 执行耗时: " + duration + "ms");return result;}
}

2. 业务类

// service/DataProcessor.java
@Service
public class DataProcessor {public void process() throws InterruptedException {Thread.sleep(500); // 模拟耗时操作}
}

3. 测试输出

方法 process 执行耗时: 503ms

4. 缓存处理(Caching)

场景:缓存方法返回值,减少重复计算。

代码实现

1. 自定义缓存注解

// annotation/Cacheable.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cacheable {String keyPrefix() default "";int ttl() default 300; // 缓存时间(秒)
}

2. 切面逻辑

// aop/CacheAspect.java
@Aspect
@Component
public class CacheAspect {private Map<String, Object> cache = new ConcurrentHashMap<>();@Around("@annotation(cacheable)")public Object handleCache(ProceedingJoinPoint pjp, Cacheable cacheable) throws Throwable {String key = cacheable.keyPrefix() + Arrays.toString(pjp.getArgs());if (cache.containsKey(key)) {System.out.println("从缓存获取数据: " + key);return cache.get(key);}Object result = pjp.proceed();cache.put(key, result);System.out.println("将数据存入缓存: " + key);return result;}
}

3. 业务类使用

// service/ProductService.java
@Service
public class ProductService {@Cacheable(keyPrefix = "product:")public String getProductInfo(String productId) {System.out.println("实际查询数据库...");return "Info-" + productId;}
}

4. 测试结果

productService.getProductInfo("P100"); // 输出: 实际查询数据库... 将数据存入缓存: product:[P100]
productService.getProductInfo("P100"); // 输出: 从缓存获取数据: product:[P100]

5. 重试机制(Retry)

场景:在方法执行失败时自动重试。

代码实现

1. 自定义重试注解

// annotation/Retry.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Retry {int maxAttempts() default 3;
}

2. 切面逻辑

// aop/RetryAspect.java
@Aspect
@Component
public class RetryAspect {@Around("@annotation(retry)")public Object retryOperation(ProceedingJoinPoint pjp, Retry retry) throws Throwable {int attempts = 0;Exception lastException;do {attempts++;try {return pjp.proceed();} catch (Exception e) {lastException = e;System.out.println("第 " + attempts + " 次尝试失败");}} while (attempts < retry.maxAttempts());throw lastException;}
}

3. 业务类使用

// service/PaymentService.java
@Service
public class PaymentService {private int callCount = 0;@Retry(maxAttempts = 5)public void processPayment() {callCount++;if (callCount < 3) {throw new RuntimeException("支付网关超时");}System.out.println("支付成功!");}
}

4. 测试输出

第 1 次尝试失败
第 2 次尝试失败
支付成功!

6. 事务管理(Transaction Management)

场景:自动管理数据库事务(简化版示例)。

代码实现

1. 事务管理器伪代码

// util/TransactionManager.java
@Component
public class TransactionManager {public void begin() {System.out.println("开启事务");}public void commit() {System.out.println("提交事务");}public void rollback() {System.out.println("回滚事务");}
}

2. 切面逻辑

// aop/TransactionAspect.java
@Aspect
@Component
public class TransactionAspect {@Autowiredprivate TransactionManager txManager;@Around("@annotation(com.example.annotation.Transactional)")public Object manageTransaction(ProceedingJoinPoint pjp) throws Throwable {txManager.begin();try {Object result = pjp.proceed();txManager.commit();return result;} catch (Exception e) {txManager.rollback();throw e;}}
}

3. 业务类使用

// service/OrderService.java
@Service
public class OrderService {@Transactionalpublic void createOrder() {System.out.println("执行订单创建逻辑...");// 模拟数据库操作}
}

4. 测试输出

开启事务
执行订单创建逻辑...
提交事务

7. 接口限流(Rate Limiting)

场景:限制接口的调用频率。

代码实现

1. 限流注解

// annotation/RateLimit.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {int value() default 5; // 每秒允许的最大请求数
}

2. 切面逻辑

// aop/RateLimitAspect.java
@Aspect
@Component
public class RateLimitAspect {private Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();@Around("@annotation(rateLimit)")public Object limit(ProceedingJoinPoint pjp, RateLimit rateLimit) throws Throwable {String methodName = pjp.getSignature().toShortString();RateLimiter limiter = limiters.computeIfAbsent(methodName, k -> RateLimiter.create(rateLimit.value()));if (limiter.tryAcquire()) {return pjp.proceed();} else {throw new RuntimeException("接口请求过于频繁");}}
}

3. 业务类使用

// service/ApiService.java
@Service
public class ApiService {@RateLimit(2) // 每秒最多2次调用public String getData() {return "敏感数据";}
}

总结表格

应用场景核心注解通知类型关键实现技术
日志记录@Loggable@AroundSlf4j + 方法元数据获取
权限校验@RequireRole@Before权限上下文 + 条件判断
性能监控无(使用execution)@Around时间计算 + 方法过滤
缓存处理@Cacheable@Around本地缓存(ConcurrentHashMap)
重试机制@Retry@Around循环控制 + 异常捕获
事务管理@Transactional@Around事务管理器模拟
接口限流@RateLimit@AroundRateLimiter + 方法标识管理

注意事项

  1. 所有切面类必须被 Spring 扫描到(确保包路径正确)
  2. 同类内部方法调用不会触发 AOP(需通过代理对象调用)
  3. 性能敏感场景慎用 AOP(会增加方法调用栈深度)

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

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

相关文章

开始一个vue项目-day2

这次新增的功能有&#xff1a; 1、使用cookie存储token 参考网站:https://vueuse.org/ 安装包&#xff1a; npm i vueuse/integrations npm i universal-cookie^7 2、cookie的设置读取和删除&#xff0c;代码&#xff1a;composables/auth.js import { useCookies } from …

「Mac畅玩AIGC与多模态18」开发篇14 - 多字段输出与结构控制工作流示例

一、概述 本篇在输入变量基础上,演示如何通过执行 LLM 节点输出多个结构化字段,并传递至结束节点。开发人员将掌握如何配置结构化输出格式,实现提示词与字段的准确映射,为后续引入条件判断、循环结构等逻辑控制建立结构输出规范基础。 二、环境准备 macOS 系统Dify 平台已…

JWT解析

什么是JWT JSON Web Token &#xff08;JWT&#xff09; 是一种开放标准 &#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且独立的方式&#xff0c;用于在各方之间以 JSON 对象的形式安全地传输信息。此信息可以验证和信任&#xff0c;因为它是经过数字签名的。…

C语言中的自定义类型 —— 结构体.位段.联合体和枚举

自定义类型 1. 前言2. 结构体2.1 结构体的声明2.2 结构体变量的定义和初始化2.3 结构体的特殊声明2.4 结构体的自引用2.5 结构体的内存对齐2.6 修改默认对齐数2.7 结构体传参 3. 位段4. 联合体5. 枚举6. 结言 1. 前言 在C语言中已经为用过户提供了内置类型&#xff0c;如&…

StarRocks 查询优化器深度解析

StarRocks 查询优化器概览 1. Development History of StarRocks 过去五年&#xff0c;StarRocks 发布了三个大版本&#xff1a; StarRocks 1.0&#xff1a;通过向量化引擎和 CBO&#xff0c;打造极速 OLAP 数据库。 StarRocks 2.0&#xff1a;通过主键模型、数据湖分析和查询…

如何提高情商?(优化版)

引言 提高情商&#xff08;EQ&#xff09;是一个需要长期练习和自我反思的过程&#xff0c;核心在于理解自己、管理情绪、共情他人并有效沟通。以下是一些具体且可操作的方法&#xff0c;结合理论和实际场景&#xff0c;帮助你逐步提升&#xff1a; 一、核心方法&#xff1a;…

Python爬虫实战:获取好大夫在线各专业全国医院排行榜数据并分析,为患者就医做参考

一、引言 在当今医疗资源丰富但分布不均的背景下,患者在选择合适的心血管内科医院时面临诸多困难。好大夫在线提供的医院排行榜数据包含了医院排名、线上服务得分、患者评价得分等重要信息,对患者选择医院具有重要的参考价值。本研究通过爬取该排行榜数据,并进行深入分析,…

【AI面试准备】电商购物车AI测试设计与实施

面试题&#xff1a;案例实践&#xff1a; 为电商购物车设计AI测试&#xff1a;通过用户行为日志训练点击路径预测模型&#xff0c;动态生成边界条件测试用例。 为了顺利通过面试&#xff0c;回答应结构清晰、技术深入&#xff0c;并突出实际应用与创新。以下为分步解答&#…

Java 中使用 Callable 创建线程的方法

一、Callable 接口概述​ Callable接口位于java.util.concurrent包中&#xff0c;与Runnable接口类似&#xff0c;同样用于定义线程执行的任务&#xff0c;但它具有以下独特特性&#xff1a;​ 支持返回值&#xff1a;Callable接口声明了一个call()方法&#xff0c;该方法会在…

2025-SMS短信验证服务或存风险,小心账号隐私“失守”

近期&#xff0c;火绒安全情报中心监测到一款伪装成具备SMS短信验证码接收服务的程序。该程序通过部署持久化后门&#xff08;即僵尸网络节点&#xff09;窃取敏感信息。火绒安全提醒广大用户务必从官方或可信渠道下载软件&#xff0c;避免因使用来路不明的程序而导致账号被盗或…

docker部署Open WebUI下载速度慢解决方法

docker pull ghcr.nju.edu.cn/open-webui/open-webui:main改成这个就可以了

气泡图、桑基图的绘制

1、气泡图 使用气泡图分析某一年中国同欧洲各国之间的贸易情况。 气泡图分析的三个维度&#xff1a; • 进口额&#xff1a;横轴 • 出口额&#xff1a;纵轴 • 进出口总额&#xff1a;气泡大小 数据来源&#xff1a;链接: 国家统计局数据 数据概览&#xff08;进出口总额&…

前端面经-VUE3篇(三)--vue Router(二)导航守卫、路由元信息、路由懒加载、动态路由

一、导航守卫 vue Router 中的 导航守卫&#xff08;Navigation Guards&#xff09; 是一个非常重要的功能&#xff0c;用于在路由切换过程中&#xff0c;拦截、控制、检查或延迟页面跳转。 你可以理解为&#xff1a; &#x1f510; “进门前的保安”&#xff0c;控制哪些页面…

MATLAB实现二氧化硅和硅光纤的单模光波特性与仿真

一.二氧化硅和硅光纤的单模光波特性 利用麦克斯方程的精确解研究二氧化硅和硅亚波长直径导线的单模光波特性。研究了单模条件、模场。 二氧化硅光纤导线是圆形截面&#xff0c;包层是空气包层&#xff0c;阶梯型变化的折射率&#xff0c;导线线径D非常小长度足够长&#xff0…

【Linux系统】第二节—基础指令(2)

hello ~ 好久不见 自己想要的快乐要自己好好争取&#xff01; 云边有个稻草人-个人主页 Linux—本篇文章所属专栏—欢迎订阅—持续更新中 目录 本节课核心指令知识点总结 本节基本指令详解 07.man 指令 08.cp 指令 09.mv 指令 10.cat 指令 11.more 指令 12.less 指令 …

为了结合后端而学习前端的学习日志——【黑洞光标特效】

前端设计专栏 今天给大家带来一个超酷的前端特效——黑洞光标&#xff01;让你的鼠标变成一个会吞噬光粒子的迷你黑洞&#xff0c;点击时还会喷射出绿色能量粒子&#xff01;&#x1f320; &#x1f680; 效果预览 想象一下&#xff1a;你的鼠标变成一个旋转的黑洞&#xff0…

[硬件电路-11]:模拟电路常见元器件 - 什么是阻抗、什么是输入阻抗、什么是输出阻抗?阻抗、输入阻抗与输出阻抗的全面解析

1. 阻抗&#xff08;Impedance&#xff09; 定义&#xff1a;阻抗是电路或元件对交流信号&#xff08;AC&#xff09;流动的阻碍能力&#xff0c;用符号Z表示&#xff0c;单位为欧姆&#xff08;Ω&#xff09;。它综合了电阻&#xff08;R&#xff09;、电感&#xff08;L&am…

机器学习和深度学习的对比

深度 数据经过深层网络后&#xff0c;语义信息表征能力强&#xff0c;对几何细节信息表征能力弱。 数据依赖性 深度学习算法需要大量的数据来训练&#xff0c;而传统的机器学习使用制定的规则。所以&#xff0c;当数据量少时&#xff0c;深度学习的性能差于机器学习&#xf…

Kubernetes 安装 minikube

安装 minikube 在 Ubuntu 上安装 minikube minikube 是一个工具&#xff0c;它可以在本地快速运行一个单节点的 Kubernetes 集群。它主要用于&#xff1a;本地学习 Kubernetes、测试和开发 Kubernetes 应用程序、快速尝试 Kubernetes 的功能。 系统配置最低要求如下 CPU&#…

【学习笔记】深度学习:典型应用

作者选择了由 Ian Goodfellow、Yoshua Bengio 和 Aaron Courville 三位大佬撰写的《Deep Learning》(人工智能领域的经典教程&#xff0c;深度学习领域研究生必读教材),开始深度学习领域学习&#xff0c;深入全面的理解深度学习的理论知识。 之前的文章参考下面的链接&#xf…