欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot使用自定義注解+AOP+Redis實現(xiàn)接口限流的實例代碼

 更新時間:2022年09月07日 11:51:04   作者:Jae1995  
這篇文章主要介紹了SpringBoot使用自定義注解+AOP+Redis實現(xiàn)接口限流,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

為什么要限流

系統(tǒng)在設計的時候,我們會有一個系統(tǒng)的預估容量,長時間超過系統(tǒng)能承受的TPS/QPS閾值,系統(tǒng)有可能會被壓垮,最終導致整個服務不可用。為了避免這種情況,我們就需要對接口請求進行限流。

所以,我們可以通過對并發(fā)訪問請求進行限速或者一個時間窗口內(nèi)的的請求數(shù)量進行限速來保護系統(tǒng)或避免不必要的資源浪費,一旦達到限制速率則可以拒絕服務、排隊或等待。

限流背景

系統(tǒng)有一個獲取手機短信驗證碼的接口,因為是開放接口,所以為了避免用戶不斷的發(fā)送請求獲取驗證碼,防止惡意刷接口的情況發(fā)生,于是用最簡單的計數(shù)器方式做了限流,限制每個IP每分鐘只能請求一次,然后其他每個手機號的時間窗口限制則是通過業(yè)務邏輯進行判斷。一般一些接口訪問量比較大的,可能會壓垮系統(tǒng)的,則需要加入流量限制!如:秒殺等...

實現(xiàn)限流

1、引入依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>       

2、自定義限流注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimiter
{
    /**
     * 限流key
     */
     String key() default Constants.RATE_LIMIT_KEY;

    /**
     * 限流時間,單位秒
     */
     int time() default 60;

    /**
     * 限流次數(shù)
     */
    int count() default 100;

    /**
     * 限流類型
     */
    LimitType limitType() default LimitType.DEFAULT;

    /**
     * 限流后返回的文字
     */
    String limitMsg() default "訪問過于頻繁,請稍候再試";
}

3、限流切面

@Aspect
@Component
public class RateLimiterAspect {

    private final static Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);

    @Autowired
    private RedisUtils redisUtils;

    @Before("@annotation(rateLimiter)")
    public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable
    {
        int time = rateLimiter.time();
        int count = rateLimiter.count();
        long total = 1L;

        String combineKey = getCombineKey(rateLimiter, point);
        try
        {
            if(redisUtils.hasKey(combineKey)){
                total = redisUtils.incr(combineKey,1);  //請求進來,對應的key加1
                if(total > count)
                    throw new ServiceRuntimeException(rateLimiter.limitMsg());
            }else{
                redisUtils.set(combineKey,1,time);  //初始化key
            }
        }
        catch (ServiceRuntimeException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new ServiceRuntimeException("網(wǎng)絡繁忙,請稍候再試");
        }
    }

    /**
     * 獲取限流key
     * @param rateLimiter
     * @param point
     * @return
     */
    public String getCombineKey(RateLimiter rateLimiter, JoinPoint point)
    {
        StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
        if (rateLimiter.limitType() == LimitType.IP)
        {
            stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest())).append("-");
        }
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Class<?> targetClass = method.getDeclaringClass();
        stringBuffer.append(targetClass.getName()).append("-").append(method.getName());
        return stringBuffer.toString();
    }
}

4、寫一個簡單的接口進行測試

@RestController
public class TestController {

    @RateLimiter(time = 60, count = 1, limitType = LimitType.IP, limitMsg = "一分鐘內(nèi)只能請求一次,請稍后重試")
    @GetMapping("/hello")
    public ResultMsg hello() {
        return ResultMsg.success("Hello World!");
    }
}

5、全局異常攔截

@RestControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 業(yè)務異常
     */
    @ExceptionHandler(ServiceRuntimeException.class)
    public ResultMsg handleServiceException(ServiceRuntimeException e, HttpServletRequest request)
    {
        return ResultMsg.error(e.getMessage());
    }

    /**
     * 系統(tǒng)異常
     */
    @ExceptionHandler(Exception.class)
    public ResultMsg handleException(Exception e, HttpServletRequest request)
    {
        return ResultMsg.error("系統(tǒng)異常");
    }
}

6、接口測試

1)第一次發(fā)送,正常返回結(jié)果

2)一分鐘內(nèi)第二次發(fā)送,返回錯誤,限流提示

好了,大功告成啦

還有其他的限流方式,如滑動窗口限流方式(比計數(shù)器更嚴謹)、令牌桶等...,有興趣的小伙伴可以學習一下

附源碼

https://gitee.com/jae_1995/ratelimiter

到此這篇關于SpringBoot使用自定義注解+AOP+Redis實現(xiàn)接口限流的文章就介紹到這了,更多相關SpringBoot接口限流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java中抽象類和接口的用法詳解

    Java中抽象類和接口的用法詳解

    這篇文章主要為大家詳細介紹了Java中抽象類和接口的使用,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-08-08
  • Java封裝公共Result結(jié)果返回類的實現(xiàn)

    Java封裝公共Result結(jié)果返回類的實現(xiàn)

    在使用Java開發(fā)接口請求中,我們需要對請求進行進行統(tǒng)一返回值,這時候我們自己封裝一個統(tǒng)一的Result返回類,本文主要介紹了Java封裝公共Result結(jié)果返回類的實現(xiàn),感興趣的可以了解一下
    2023-01-01
  • 淺談java實現(xiàn)redis的發(fā)布訂閱(簡單易懂)

    淺談java實現(xiàn)redis的發(fā)布訂閱(簡單易懂)

    本篇文章主要介紹了淺談java實現(xiàn) redis的發(fā)布訂閱(簡單易懂),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • Idea如何使用Fast Request接口調(diào)試

    Idea如何使用Fast Request接口調(diào)試

    這篇文章主要介紹了Idea如何使用Fast Request接口調(diào)試問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Spring?Boot?3.4.3?基于?Spring?WebFlux?實現(xiàn)?SSE?功能(代碼示例)

    Spring?Boot?3.4.3?基于?Spring?WebFlux?實現(xiàn)?SSE?功能(代碼示例)

    Spring Boot 3.4.3 結(jié)合Spring WebFlux實現(xiàn)SSE 功能,為實時數(shù)據(jù)推送提供了優(yōu)雅的解決方案,通過本文的步驟,你可以快速搭建一個基于事件驅(qū)動的后端服務,滿足實時通知或監(jiān)控等需求,感興趣的朋友一起看看吧
    2025-04-04
  • Java實現(xiàn)簡單版貪吃蛇游戲

    Java實現(xiàn)簡單版貪吃蛇游戲

    這篇文章主要為大家詳細介紹了Java實現(xiàn)簡單版貪吃蛇游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 使用Java實現(xiàn)HTTP和HTTPS代理服務詳解

    使用Java實現(xiàn)HTTP和HTTPS代理服務詳解

    這篇文章主要為大家詳細介紹了如何使用Java實現(xiàn)HTTP和HTTPS代理服務,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-04-04
  • Java中讀取YAML文件配置信息常見問題及解決方法

    Java中讀取YAML文件配置信息常見問題及解決方法

    這篇文章主要介紹了Java中讀取YAML文件配置信息常見問題及解決方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2025-07-07
  • Springboot實現(xiàn)MQTT通信的示例代碼

    Springboot實現(xiàn)MQTT通信的示例代碼

    本文主要介紹了Springboot實現(xiàn)MQTT通信的示例代碼,包含了MQTT協(xié)議的特點和工作原理等,具有一定的參考價值,感興趣的可以了解一下
    2025-01-01
  • 使用FeignClient調(diào)用遠程服務時整合本地的實現(xiàn)方法

    使用FeignClient調(diào)用遠程服務時整合本地的實現(xiàn)方法

    這篇文章主要介紹了使用FeignClient調(diào)用遠程服務時整合本地的實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03

最新評論