JAVA:Spring Boot 集成 Guava 实现流量控制

admin
11
2025-09-26

🚦 1、简述

在高并发场景下,系统如果没有做流量控制,可能会因为请求突增导致 服务过载甚至宕机。常见的限流算法包括:

🔹 固定窗口计数器

🔹 滑动窗口

🔹 令牌桶(Token Bucket)

🔹 漏桶(Leaky Bucket)

样例代码:https://gitee.com/lhdxhl/springboot-example.git

Google 的 Guava 库提供了一个非常优雅的限流工具类:RateLimiter,它基于令牌桶算法实现,能够轻松限制 QPS(每秒请求数)。

image-lyix.png


2、 原理

🔹 RateLimiter.create(double permitsPerSecond):创建一个限流器,每秒生成 permitsPerSecond 个令牌。

🔹 acquire():从桶里获取一个令牌,如果没有则阻塞等待。

🔹 tryAcquire():尝试获取令牌,如果没有则立即返回 false

这种方式非常适合 Web 服务的接口限流场景。

image-8egf.png


3、实践样例

3.1 引入依赖

Spring Boot 项目的 pom.xml 中添加:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>32.1.3-jre</version>
</dependency>

3.2 定义限流配置类

import com.google.common.util.concurrent.RateLimiter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RateLimiterConfig {

    @Bean
    public RateLimiter rateLimiter() {
        // 每秒只允许 5 个请求
        return RateLimiter.create(5.0);
    }
}

3.2 控制器使用限流

import com.google.common.util.concurrent.RateLimiter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    private final RateLimiter rateLimiter;

    public DemoController(RateLimiter rateLimiter) {
        this.rateLimiter = rateLimiter;
    }

    @GetMapping("/api/hello")
    public String hello() {
        // 尝试获取令牌(非阻塞)
        if (!rateLimiter.tryAcquire()) {
            return "请求过多,请稍后再试!";
        }
        return "Hello, 请求成功!";
    }
}

3.3 使用 AOP 对接口统一限流(更优雅)

可以通过注解和切面实现 不同接口不同限流规则

① 自定义注解

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {
    double permitsPerSecond(); // 每秒放行请求数
}

② 切面实现

import com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;

@Aspect
@Component
public class RateLimitAspect {

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

    @Around("@annotation(rateLimit)")
    public Object around(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
        String key = joinPoint.getSignature().toShortString();
        RateLimiter rateLimiter = limiters.computeIfAbsent(key,
                k -> RateLimiter.create(rateLimit.permitsPerSecond()));

        if (!rateLimiter.tryAcquire()) {
            return "接口被限流,请稍后再试!";
        }
        return joinPoint.proceed();
    }
}

③ 控制器使用注解

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ApiController {

    @RateLimit(permitsPerSecond = 2.0) // 每秒最多 2 次请求
    @GetMapping("/api/data")
    public String getData() {
        return "成功返回数据";
    }
}

3.4 测试效果

🔹 启动 Spring Boot 应用;

🔹 快速刷新 /api/data 接口;

🔹 你会发现大部分请求返回 "接口被限流,请稍后再试!"

这样,我们就利用 Guava + Spring Boot 快速实现了接口限流。


4、总结

🔹 RateLimiter 基于 令牌桶算法,适合做接口级别的限流;

🔹 简单场景下可以直接在 Controller 使用;

🔹 复杂场景推荐通过 注解 + AOP,实现多接口灵活限流;

🔹 如果需要分布式限流,可以结合 Redis、Sentinel 等工具。

动物装饰