当前位置:首页 > 技术 > 正文内容

Spring Boot 接口限流实战:基于 Guava 令牌桶与 AOP 的实现方案

访客 技术 2026年6月4日 1

在单体 Spring Boot 项目中,若需对接口进行流量管控,无需引入网关组件,可借助 Guava 的 RateLimiter 结合 AOP 切面编程快速实现。以下为完整的技术方案。

依赖引入

pom.xml 中添加 Guava 与 AOP 支持:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>32.1.3-jre</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

自定义限流注解

定义 @RateLimit 注解,用于标注需要限流的方法:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {
    /**
     * 限流标识,需全局唯一
     */
    String resourceKey();

    /**
     * 每秒生成的令牌数量
     */
    double qps();

    /**
     * 获取令牌的最大等待时长
     */
    long waitTime() default 0;

    /**
     * 等待时长的单位
     */
    TimeUnit unit() default TimeUnit.MILLISECONDS;

    /**
     * 触发限流时的提示信息
     */
    String fallbackMessage() default "请求过于频繁,请稍后重试";
}

切面逻辑实现

通过 AOP 拦截注解,利用 ConcurrentHashMap 维护各资源对应的限流器实例:

@Slf4j
@Aspect
@Component
public class RateLimitInterceptor {

    private final Map<String, RateLimiter> rateLimiterCache = new ConcurrentHashMap<>();

    @Around("@annotation(rateLimit)")
    public Object intercept(ProceedingJoinPoint point, RateLimit rateLimit) throws Throwable {
        String resource = rateLimit.resourceKey();
        
        RateLimiter limiter = rateLimiterCache.computeIfAbsent(resource, k -> 
            RateLimiter.create(rateLimit.qps())
        );

        boolean permitted = limiter.tryAcquire(rateLimit.waitTime(), rateLimit.unit());
        if (!permitted) {
            return buildErrorResponse(rateLimit.fallbackMessage());
        }

        return point.proceed();
    }

    private Object buildErrorResponse(String message) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) 
            RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = attributes.getResponse();
        
        response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        
        try (PrintWriter writer = response.getWriter()) {
            writer.write("{\"error\":\"" + message + "\"}");
        } catch (IOException ex) {
            log.error("限流响应写入失败", ex);
        }
        return null;
    }
}

接口应用示例

在 Controller 方法上添加注解,实现每 500 毫秒仅允许 1 次请求:

@RestController
@RequestMapping("/api")
public class DataSyncController {

    @PostMapping("/fetch")
    @RateLimit(resourceKey = "data-fetch", qps = 2.0, waitTime = 500, unit = TimeUnit.MILLISECONDS)
    public ResponseEntity<String> fetchExternalData() {
        return ResponseEntity.ok("数据处理完成");
    }
}

关键注意点

  • 资源标识唯一性resourceKey 需保证全局唯一,相同 key 共享同一限流器
  • QPS 计算方式RateLimiter.create(2.0) 表示每秒生成 2 个令牌,即每 500ms 1 个
  • 异常处理:建议将限流响应封装为统一 Result 对象,便于前端处理
  • 内存管理:当前实现基于内存缓存,重启后限流器状态丢失,生产环境可考虑 Redis 持久化方案

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。