侧边栏壁纸
博主头像
叶落无痕

鸿雁长飞光不度,鱼龙潜跃水成文。

  • 累计撰写 11 篇文章
  • 累计创建 7 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

基于AOP+注解实现接口限流

yeluo
2024-11-25 / 0 评论 / 0 点赞 / 23 阅读 / 0 字
温馨提示:
本文最后更新于2024-11-25,若内容或图片失效,请留言反馈。 部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

使用注解形式,进行接口的动态限流配置

  1. 添加依赖项

<!--  springboot 整合web组件-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>
  1. 编写注解ApiLimit

package com.test.config.limit;

import java.lang.annotation.*;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiLimit {

    /**
     * 名称
     * @return
     */
    String name();

    /**
     * 限速每秒生成token数量
     * @return
     */
    double token() default 1.0;

}
  1. 编写ApiLimitAspect

package com.test.config.limit;

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.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@Aspect
@Component
public class ApiLimitAspect {

    protected Logger logger = LoggerFactory.getLogger(getClass());

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

    @Pointcut("@annotation(com.test.config.limit.ApiLimit)"
            + "|| @within(com.test.config.limit.ApiLimit)")
    public void dsPointCut() {

    }

    @Around("dsPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        ApiLimit apiLimit = getApiLimit(point);

        if (Objects.nonNull(apiLimit)){
            // 获取注解上的name
            String name = apiLimit.name();
            // 获取注解上的token
            double token = apiLimit.token();
            RateLimiter rateLimiter = rateLimiters.get(name);
            if (rateLimiter == null) {
                rateLimiter = RateLimiter.create(token);
                rateLimiters.put(name, rateLimiter);
            }
            // 开始限流
            boolean result = rateLimiter.tryAcquire();
            if (!result) {
                return "当前访问人数过多,请稍后重试!";
            }
        }
        return point.proceed();
    }

    /**
     * 获取限速注解
     */
    public ApiLimit getApiLimit(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        ApiLimit apiLimit = AnnotationUtils.findAnnotation(signature.getMethod(), ApiLimit.class);
        if (Objects.nonNull(apiLimit)) {
            return apiLimit;
        }
        return AnnotationUtils.findAnnotation(signature.getDeclaringType(), ApiLimit.class);
    }
}
  1. 在使用的方法或类型添加限速注解

@GetMapping("/add")
@ApiLimit(name = "add", token = 5)
public String add() {
    return "my is add";
}

0

评论区