@accesslimit注解通过aop切面+redis原子操作实现精准限流,支持ip/用户/uri等维度计数,强制返回429状态码及retry-after头,集群下需redis高可用与带业务上下文的key设计。

直接用标准自定义注解“强行锁死”特定接口的并发访问量,核心不是靠注解本身,而是靠注解触发的限流逻辑。注解只是标记,真正起作用的是背后的AOP切面或拦截器 + 存储计数器(Redis最常用)。下面说清楚怎么落地,不绕弯子。
定义规范、可复用的限流注解
注解要明确表达意图,字段语义清晰,支持按IP、用户、接口路径等维度区分限流单位:
- @AccessLimit:类名统一,避免和Spring内置注解混淆
- count():指定时间窗口内允许的最大请求数(如 5)
- seconds():时间窗口长度(如 60),单位固定为秒,不混用毫秒
- keyType():枚举类型,取值如 IP、USER_ID、URI、CUSTOM,决定计数key怎么拼
- fallbackMsg():限流触发时返回的提示语,方便前端统一处理
用AOP切面接管请求,实时校验并发量
注解生效必须绑定执行逻辑。推荐用 @Aspect + @Before 或 @Around:
- 在切面中解析注解参数,生成唯一限流key(例如:ip:192.168.1.100:api/v1/user/profile)
- 调用 Redis 的 INCR + EXPIRE 原子操作(或用
SET key value EX seconds NX配合 Lua 脚本防竞态) - 若 INCR 后值 > count,立即抛出
ResponseStatusException(HttpStatus.TOO_MANY_REQUESTS),不进 Controller - 避免用本地 Map 或静态变量——无法跨实例,集群下完全失效
关键细节必须卡死
所谓“强行锁死”,体现在三处不可妥协的设计:
- Redis 必须开启持久化+高可用:单点 Redis 故障会导致限流失效,等于裸奔;建议用 Redis Sentinel 或 Cluster
-
限流key必须带业务上下文:比如短信发送接口,仅按 IP 限流不够,得组合手机号(
ip:xxx:phone:138****1234),否则恶意用户换号就绕过 -
拒绝响应必须是标准HTTP状态码:返回 429 Too Many Requests,并附带
Retry-After: 60头,符合 RFC 6585,前端/网关能自动识别
后台管理系统特别注意事项
管理后台通常有登录态、角色权限,比开放API更可控,可做精准压制:
- 对超级管理员(admin)可设
pass = true属性,注解里直接放行,避免误伤运维 - 敏感操作接口(如删除用户、导出全部数据)强制标注
@AccessLimit(count = 1, seconds = 300),5分钟仅允一次 - 结合 Spring Security,从
SecurityContextHolder.getContext().getAuthentication()提取用户名,作为 key 一部分,实现“每人每小时最多导出3次”











