开发喵星球

控制器实现限流

用户:

springboot实现一个控制器,控制器是get请求,名字show,用注解的方式实现该接口每分钟只能访问5次

ChatGPT:

要实现这个功能,您可以使用Spring Boot的@RestController@GetMapping注解创建一个名为show的GET请求控制器。然后,您可以使用RateLimiter来限制每分钟访问次数。这里是一个简单的示例:

首先,添加Guava依赖到您的pom.xml文件中:

<dependencies>
    <!-- other dependencies -->
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>30.1-jre</version>
    </dependency>
</dependencies>

然后,创建一个名为RateLimiterAspect的切面类,用于限制每分钟访问次数:

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

@Aspect
@Component
public class RateLimiterAspect {

    private final RateLimiter rateLimiter = RateLimiter.create(5.0 / 60.0); // 5 permits per minute

    @Before("@annotation(com.example.demo.RateLimited)")
    public void rateLimit() {
        rateLimiter.acquire();
    }
}

接下来,创建一个自定义注解RateLimited

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RateLimited {
}

最后,创建一个名为show的GET请求控制器,并使用@RateLimited注解限制每分钟访问次数:

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

@RestController
public class ShowController {

    @RateLimited
    @GetMapping("/show")
    public String show() {
        return "Hello, this is the show endpoint!";
    }
}

现在,当您尝试访问/show端点时,每分钟只能访问5次。请注意,这个简单的示例没有处理并发访问的情况,如果您需要在高并发环境下使用,请考虑使用更复杂的限流策略。

用户:

不同的接口每分钟访问次数不一样

ChatGPT:

为了实现不同接口每分钟访问次数不一样的限制,您可以在自定义的RateLimited注解中添加一个属性,用于指定每分钟的访问次数。然后,在RateLimiterAspect中为每个接口创建一个单独的RateLimiter实例。

首先,修改RateLimited注解,添加一个名为value的属性:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RateLimited {
    double value();
}

接下来,修改RateLimiterAspect类,为每个接口创建一个单独的RateLimiter实例:

import com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Aspect
@Component
public class RateLimiterAspect {

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

    @Before("@annotation(com.example.demo.RateLimited)")
    public void rateLimit(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        RateLimited rateLimited = method.getAnnotation(RateLimited.class);
        double permitsPerMinute = rateLimited.value();

        RateLimiter rateLimiter = rateLimiterMap.computeIfAbsent(method.getName(), k -> RateLimiter.create(permitsPerMinute / 60.0));
        rateLimiter.acquire();
    }
}

现在,您可以在不同的接口上使用@RateLimited注解,并指定每分钟的访问次数。例如:

@RestController
public class MyController {

    @RateLimited(5)
    @GetMapping("/show1")
    public String show1() {
        return "Hello, this is the show1 endpoint!";
    }

    @RateLimited(10)
    @GetMapping("/show2")
    public String show2() {
        return "Hello, this is the show2 endpoint!";
    }
}

在这个示例中,show1接口每分钟只能访问5次,而show2接口每分钟可以访问10次。

用户:

不用goole这个依赖com.google.guava

ChatGPT:

如果您不想使用Guava库,可以使用Java的Semaphore类来实现类似的功能。以下是一个不使用Guava的实现:

首先,修改RateLimiterAspect类,使用Semaphore替代RateLimiter

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class RateLimiterAspect {

    private final Map<String, Semaphore> semaphoreMap = new ConcurrentHashMap<>();

    @Before("@annotation(com.example.demo.RateLimited)")
    public void rateLimit(JoinPoint joinPoint) throws InterruptedException {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        RateLimited rateLimited = method.getAnnotation(RateLimited.class);
        int permitsPerMinute = (int) rateLimited.value();

        Semaphore semaphore = semaphoreMap.computeIfAbsent(method.getName(), k -> new Semaphore(permitsPerMinute));
        semaphore.tryAcquire(1, TimeUnit.MINUTES);
    }
}

请注意,这个实现可能不如Guava的RateLimiter精确,因为它使用的是Semaphore,而不是基于令牌桶算法的RateLimiter。但是,这个实现可以在不使用Guava的情况下为您提供基本的限流功能。

   
分类:未分类 作者:吃我一拂尘 发表于:2023-12-11 03:39:50 阅读量:101
<<   >>


powered by kaifamiao