Spring AOP 进阶实战:从日志到权限/链路追踪/限流(真正企业用法)
一、前言
上一篇
Spring AOP 从原理到实战(结合事务彻底搞懂)
我们已经搞懂了:
✔ AOP 原理
✔ @Before / @After / @Around 的区别
✔ 事务为什么用 AOP
但是很多人学完之后,会有一个问题:AOP 到底在项目里怎么用?
这一篇,我们不再讲“语法”,而是讲:
企业项目中,AOP 真正用在哪些地方?什么时候用?
二、AOP 的本质再理解(关键)
先记住一句话:
AOP = 把“非业务逻辑”从业务代码里抽离
比如:
| 类型 | 是否业务 |
|---|---|
| 下单、注册 | ✅ 业务 |
| 打日志 | ❌ 非业务 |
| 权限校验 | ❌ 非业务 |
| 限流 | ❌ 非业务 |
| 链路追踪 | ❌ 非业务 |
👉 所以:
AOP 专门处理:所有“横切关注点”三、企业中 AOP 常见 4 大场景
这一节是重点 👇
1️⃣ 日志 AOP(必备)
👉 使用时机:
所有接口调用都要记录: ✔ 参数 ✔ 返回值 ✔ 耗时 ✔ 异常👉 为什么用 AOP?
不可能每个 Controller 都写 log✅ 推荐写法(Around)
@Aspect @Component @Slf4j public class LogAspect { @Around("execution(* com.xxx.modules..controller..*(..))") public Object log(ProceedingJoinPoint jp) throws Throwable { long start = System.currentTimeMillis(); String method = jp.getSignature().toShortString(); try { Object result = jp.proceed(); long cost = System.currentTimeMillis() - start; log.info("接口:{},耗时:{}ms,返回:{}", method, cost, result); return result; } catch (Throwable e) { log.error("接口异常:{}", method, e); throw e; } } }什么时候用?
✔ 所有项目(必须) ✔ 第一个 AOP2️⃣ TraceId(链路追踪)
👉 使用时机:
当日志“看不懂”的时候例如:
多个用户同时请求 → 日志混在一起✅ 解决方案:
给每个请求一个唯一 ID示例:
@Aspect @Component public class TraceIdAspect { @Around("execution(* com.xxx.modules..*(..))") public Object trace(ProceedingJoinPoint jp) throws Throwable { String traceId = UUID.randomUUID().toString().replace("-", ""); MDC.put("traceId", traceId); try { return jp.proceed(); } finally { MDC.remove("traceId"); } } }logback 配置:
<pattern>%d{HH:mm:ss} [%X{traceId}] %-5level %logger - %msg%n</pattern>什么时候用?
✔ 有多个接口 ✔ 有并发 ✔ 开始调试问题 ✔ 面试加分项3️⃣ 权限控制 AOP(RBAC 基础)
👉 使用时机:
接口需要权限控制❌ 不推荐写法:
if (!isAdmin()) { throw new RuntimeException("没权限"); }👉 到处都是权限判断 ❗
✅ AOP 写法
定义注解:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface CheckPermission { String value(); }AOP:
@Aspect @Component public class PermissionAspect { @Around("@annotation(checkPermission)") public Object check(ProceedingJoinPoint jp, CheckPermission checkPermission) throws Throwable { String permission = checkPermission.value(); if (!hasPermission(permission)) { throw new RuntimeException("没有权限:" + permission); } return jp.proceed(); } }使用:
@CheckPermission("user:add") @PostMapping("/add") public String addUser() { return "ok"; }什么时候用?
✔ 有登录系统 ✔ 有角色权限(admin/user) ✔ 企业项目必备4️⃣ 限流 AOP(高并发保护)
👉 使用时机:
接口被频繁调用 / 防刷 / 防攻击示例:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RateLimit { int limit(); }@Aspect @Component public class RateLimitAspect { private final Map<String, AtomicInteger> counter = new ConcurrentHashMap<>(); @Around("@annotation(rateLimit)") public Object limit(ProceedingJoinPoint jp, RateLimit rateLimit) throws Throwable { String key = jp.getSignature().toShortString(); counter.putIfAbsent(key, new AtomicInteger(0)); int count = counter.get(key).incrementAndGet(); if (count > rateLimit.limit()) { throw new RuntimeException("请求过多"); } return jp.proceed(); } }⚠ 实际生产:
必须用 Redis + 令牌桶什么时候用?
✔ 秒杀 ✔ 登录接口 ✔ 高频接口四、AOP 使用优先级(你该怎么学)
第一阶段(你现在)
✔ 日志 AOP(必须) ✔ Around 用法第二阶段(建议马上)
✔ TraceId ⭐⭐⭐⭐ ✔ 全局异常处理 ✔ 统一返回结构第三阶段(进阶)
✔ 权限控制 ✔ 限流 ✔ 分布式链路追踪(SkyWalking)五、AOP 使用误区(面试会问)
❌ 误区1:AOP 写业务逻辑
AOP 不处理业务,只处理“通用能力”❌ 误区2:滥用 @Before
很多逻辑必须用 @Around❌ 误区3:所有东西都用 AOP
能不用就不用,AOP是增强,不是主流程六、总结
🔥 一句话总结:
AOP = 企业级“能力插件系统”🔥 常见使用场景:
日志 → 必用 TraceId → 强烈推荐 权限控制 → 企业必备 限流 → 高并发场景🔥 最关键认知:
你不是在学 AOP,而是在搭建“基础设施能力”七、下一步建议
你可以继续做:
✔ AOP + TraceId + Logback 打通 ✔ 全局异常处理(@ControllerAdvice) ✔ 统一返回结构 Result👉 这一套做完:
= 中级后端工程能力