IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> [redisson]使用redisson限流器Ratelimiter结合自定义注解及AOP实现限流 -> 正文阅读

[Java知识库][redisson]使用redisson限流器Ratelimiter结合自定义注解及AOP实现限流

使用redisson限流器Ratelimiter实现限流,保证服务正常可用

使用的jar包:

implementation 'org.redisson:redisson-spring-boot-starter:3.13.6'

定义自定义注解

import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.springframework.web.bind.annotation.Mapping;

import java.lang.annotation.*;

/**
 * redisson限流器
 * @author liurui
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestRateLimiter {

    /**
     * 限流的key
     * @return
     */
    String key();

    /**
     * 限流模式,默认单机
     * @return
     */
    RateType type() default RateType.PER_CLIENT;

    /**
     * 限流速率,默认每秒10
     * @return
     */
    long rate() default 10;

    /**
     * 限流速率
     * @return
     */
    long rateInterval() default 1000;

    /**
     * 限流速率单位
     * @return
     */
    RateIntervalUnit timeUnit() default RateIntervalUnit.MILLISECONDS;

}

定义AOP切面

import org.apache.commons.lang3.StringUtils;
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.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Aspect
@Component
public class RequestRateLimitAspect {

    @Autowired
    private RedissonClient redisson;

    /**
     * 根据自定义注解获取切点
     * @param requestRateLimiter
     */
    @Pointcut("@annotation(requestRateLimiter)")
    public void accessLimit(RequestRateLimiter requestRateLimiter) {
    }

    @Around(value = "accessLimit(requestRateLimiter)", argNames = "pjp,requestRateLimiter")
    public Object around(ProceedingJoinPoint pjp, RequestRateLimiter requestRateLimiter) throws Throwable {
        // 限流拦截器
        RRateLimiter rRateLimiter = getRateLimiter(requestRateLimiter);
        if (rRateLimiter.tryAcquire(1)) {
            return pjp.proceed();
        } else {
            return buildErrorResult();
        }
    }

    /**
     * 获取限流拦截器
     * @param requestRateLimiter
     * @return
     */
    private RRateLimiter getRateLimiter(RequestRateLimiter requestRateLimiter){
        RRateLimiter rRateLimiter = redisson.getRateLimiter(StringUtils.isBlank(requestRateLimiter.key()) ? "default:limiter" : requestRateLimiter.key());
        // 设置限流
        if(rRateLimiter.isExists()) {
            RateLimiterConfig rateLimiterConfig = rRateLimiter.getConfig();
            // 判断配置是否更新,如果更新,重新加载限流器配置
            if (!Objects.equals(requestRateLimiter.rate(), rateLimiterConfig.getRate())
                    || !Objects.equals(requestRateLimiter.timeUnit().toMillis(requestRateLimiter.rateInterval()), rateLimiterConfig.getRateInterval())
                    || !Objects.equals(requestRateLimiter.type(), rateLimiterConfig.getRateType())) {
                rRateLimiter.delete();
                rRateLimiter.trySetRate(requestRateLimiter.type(), requestRateLimiter.rate(), requestRateLimiter.rateInterval(), requestRateLimiter.timeUnit());
            }
        } else {
            rRateLimiter.trySetRate(requestRateLimiter.type(), requestRateLimiter.rate(), requestRateLimiter.rateInterval(), requestRateLimiter.timeUnit());
        }

        return rRateLimiter;
    }

    /**
     * 没有限流令牌返回结果
     * @return
     */
    public Object buildErrorResult() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("code", "-1");
        map.put("message", "Too many people visit");
        return map;
    }

}

定义url请求:

import org.redisson.api.RateIntervalUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author liurui
 * @date 2021/11/17
 */
@RestController
@RequestMapping("/redis/test")
public class RedisController {

    private final Logger logger = LoggerFactory.getLogger(RedisController.class);

    @Autowired
    private RedisService redisService;

    @RequestMapping("/add")
    // 为方便测试,每两秒生成一个限流令牌
    @RequestRateLimiter(key = "test", rate = 1, rateInterval = 2, timeUnit = RateIntervalUnit.SECONDS)
    public Object add(String data) {
        logger.info("进入请求");
        redisService.add("testkey", data);
        return "成功";
    }
}

jmeter压测配置:
在这里插入图片描述
在这里插入图片描述

jmeter压测结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在声明的上述自定义注解和AOP切面之后,只需要在需要使用限流的请求方法上声明对应的自定义注解及参数配置即可实现限流。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-02-26 11:16:56  更:2022-02-26 11:19:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:30:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码