最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Springboot項(xiàng)目接口限流實(shí)現(xiàn)方案

 更新時(shí)間:2024年08月19日 10:22:53   作者:一棵星  
這篇文章主要介紹了Springboot項(xiàng)目接口限流實(shí)現(xiàn)方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

系統(tǒng)限流要求

  • 系統(tǒng)總并發(fā)數(shù)限制,如設(shè)置1000,表示該系統(tǒng)接口每秒可以請(qǐng)求1000次
  • 自定義系統(tǒng)接口請(qǐng)求并發(fā)數(shù),也可以不加限流設(shè)置,如設(shè)置100,表示每秒可以請(qǐng)求100次該接口
  • 指定接口IP請(qǐng)求并發(fā)數(shù),如設(shè)置1,表示每秒該IP可以請(qǐng)求1次該接口

實(shí)現(xiàn)思路

  • 每秒系統(tǒng)總并發(fā)數(shù)限流實(shí)現(xiàn),可以使用攔截器或過(guò)濾器,來(lái)處理系統(tǒng)總并發(fā)數(shù)限流的實(shí)現(xiàn)
  • 自定義系統(tǒng)接口請(qǐng)求并發(fā)數(shù)和指定接口IP請(qǐng)求并發(fā)數(shù)的實(shí)現(xiàn),可以使用自定義注解和切面,來(lái)處理自定義系統(tǒng)接口請(qǐng)求并發(fā)數(shù)的實(shí)現(xiàn)
  • 可以使用Redisson RRateLimiter組件實(shí)現(xiàn)具體限流邏輯
  • 自定義業(yè)務(wù)異常類,當(dāng)請(qǐng)求數(shù)超出請(qǐng)求限制時(shí),來(lái)打斷業(yè)務(wù)

核心代碼

1.接口限流注解

package com.ocean.angel.tool.annotation;

import java.lang.annotation.*;

/**
 * 接口限流注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ApiLimiting {

    // 接口請(qǐng)求限制數(shù)
    int apiRequestLimit() default 200;

    // 接口請(qǐng)求IP限制數(shù)
    int apiIpLimit() default 1;
}

2.接口限流切面

package com.ocean.angel.tool.aspect;

import com.ocean.angel.tool.annotation.ApiLimiting;
import com.ocean.angel.tool.constant.ApiLimitingTypeEnum;
import com.ocean.angel.tool.constant.ResultCode;
import com.ocean.angel.tool.dto.ApiLimitingData;
import com.ocean.angel.tool.exception.BusinessException;
import com.ocean.angel.tool.util.RateLimiterKeyUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * 接口限流切面
 */
@Slf4j
@Aspect
@Component
public class ApiLimitingAspect {

    @Resource
    private RedissonClient redissonClient;

    @Pointcut("@annotation(com.ocean.angel.tool.annotation.ApiLimiting)")
    public void apiLimitingAspect() {}

    @Before(value = "apiLimitingAspect()")
    public void apiLimiting(JoinPoint joinPoint) {
        ApiLimitingData apiLimitingData = getApiLimitData(joinPoint);
        rateLimiterHandler(redissonClient, apiLimitingData);
    }

    /**
     * API 限流邏輯處理
     */
    private void rateLimiterHandler(RedissonClient redissonClient, ApiLimitingData apiLimitingData) {

        if(apiLimitingData.getApiIpLimit() > 0) {

            // 獲取RRateLimiter實(shí)例
            RRateLimiter rateLimiter = redissonClient.getRateLimiter(getRateLimiterKey(apiLimitingData, ApiLimitingTypeEnum.API_IP_LIMIT));

            // RRateLimiter初始化
            if(!RateLimiterKeyUtil.contains(getRateLimiterKey(apiLimitingData, ApiLimitingTypeEnum.API_IP_LIMIT))) {
                rateLimiter.trySetRate(RateType.OVERALL, apiLimitingData.getApiIpLimit(), 1, RateIntervalUnit.SECONDS);
            }

            // 超出接口請(qǐng)求IP限流設(shè)置,打斷業(yè)務(wù)
            if (!rateLimiter.tryAcquire()) {
                log.info("接口{}超出IP請(qǐng)求限制, 時(shí)間:{}",apiLimitingData.getMethodName(), System.currentTimeMillis());
                throw new BusinessException(ResultCode.BEYOND_RATE_LIMIT);
            }
        }

        if(apiLimitingData.getApiRequestLimit() > 0) {

            RRateLimiter rateLimiter = redissonClient.getRateLimiter(getRateLimiterKey(apiLimitingData, ApiLimitingTypeEnum.API_REQUEST_LIMIT));

            if(!RateLimiterKeyUtil.contains(getRateLimiterKey(apiLimitingData, ApiLimitingTypeEnum.API_REQUEST_LIMIT))) {
                rateLimiter.trySetRate(RateType.OVERALL, apiLimitingData.getApiRequestLimit(), 1, RateIntervalUnit.SECONDS);
            }

            // 超出接口請(qǐng)求限流設(shè)置,打斷業(yè)務(wù)
            if (!rateLimiter.tryAcquire()) {
                log.info("接口{}超出請(qǐng)求限制, 時(shí)間:{}",apiLimitingData.getMethodName(), System.currentTimeMillis());
                throw new BusinessException(ResultCode.BEYOND_RATE_LIMIT);
            }
        }
    }

    /**
     * 組裝ApiLimitingData
     */
    private ApiLimitingData getApiLimitData(JoinPoint joinPoint) {

        ApiLimitingData apiLimitingData = new ApiLimitingData();

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        apiLimitingData.setMethodName(method.getName());

        ApiLimiting apiLimiting = method.getAnnotation(ApiLimiting.class);
        apiLimitingData.setApiRequestLimit(apiLimiting.apiRequestLimit());
        apiLimitingData.setApiIpLimit(apiLimiting.apiIpLimit());

        return apiLimitingData;
    }

    /**
     * RateLimiter Key
     */
    private String getRateLimiterKey(ApiLimitingData apiLimitingData, ApiLimitingTypeEnum apiLimitingTypeEnum) {
        return apiLimitingData.getMethodName() + "_" + apiLimitingTypeEnum.getCode();
    }
}

3.系統(tǒng)接口限流攔截器

package com.ocean.angel.tool.interceptor;

import com.ocean.angel.tool.constant.ResultCode;
import com.ocean.angel.tool.exception.BusinessException;
import com.ocean.angel.tool.util.RateLimiterKeyUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
public class ApiLimitingInterceptor implements HandlerInterceptor {

    private final static String API_TOTAL_LIMIT = "apiTotalLimit";

    // 系統(tǒng)每秒請(qǐng)求總數(shù),30表示每秒最多處理30個(gè)請(qǐng)求
    private final static int API_TOTAL_LIMIT_NUMBER = 30;
    private final RedissonClient redissonClient;

    public ApiLimitingInterceptor(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        RRateLimiter rateLimiter = redissonClient.getRateLimiter(API_TOTAL_LIMIT);

        if(!RateLimiterKeyUtil.contains(API_TOTAL_LIMIT)) {
            rateLimiter.trySetRate(RateType.OVERALL, API_TOTAL_LIMIT_NUMBER, 1, RateIntervalUnit.SECONDS);
        }

        // 超出系統(tǒng)接口總請(qǐng)求數(shù)限制,打斷業(yè)務(wù)
        if (!rateLimiter.tryAcquire()) {
            log.info("超出系統(tǒng)接口總請(qǐng)求數(shù)限制, 時(shí)間:{}", System.currentTimeMillis());
            throw new BusinessException(ResultCode.BEYOND_RATE_LIMIT);
        }
        return true;
    }
}

4.接口自定義注解配置

@ApiLimiting(apiRequestLimit = 5, apiIpLimit = 1)
@GetMapping("/limited/resource")
public ResultBean<?> limitedResource() {
    return ResultBean.success();
}

限流方案演示

下載源代碼,github源碼連接

修改application.yml和redission.yml,關(guān)于redis的相關(guān)配置

啟動(dòng)項(xiàng)目,調(diào)用http://localhost:8090/test/limited/resource接口,截圖如下:

保持項(xiàng)目啟動(dòng)狀態(tài),運(yùn)行com.ocean.angel.tool.ApplicationTests.contextLoads()方法,截圖如下:

使用指南

修改系統(tǒng)總請(qǐng)求數(shù)限制

調(diào)整系統(tǒng)接口限流參數(shù)

本文使用Redisson RRateLimiter組件實(shí)現(xiàn)具體限流邏輯,小伙伴們可以自己去手寫(xiě)具體限流功能(可以參考Redission的限流相關(guān)的數(shù)據(jù)結(jié)構(gòu))

注意:

小伙伴們?nèi)绻薷南到y(tǒng)限流的配置,需要先刪除redis里面的限流數(shù)據(jù)(如上圖),不然修改不會(huì)生效。

本文使用以1秒為單位進(jìn)行系統(tǒng)并發(fā)數(shù)控制,小伙伴可以根據(jù)需要自己去修改,如下:

rateLimiter.trySetRate(RateType.OVERALL, apiLimitingData.getApiIpLimit(), 1, RateIntervalUnit.SECONDS)

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring Boot 4 與 Spring Framework 7新特性、升級(jí)要點(diǎn)與實(shí)戰(zhàn)指南

    Spring Boot 4 與 Spring Framework&nb

    SpringBoot4和SpringFramework7帶來(lái)了大量新特性,包括升級(jí)到JakartaEE11、支持Java21、增強(qiáng)模塊化、優(yōu)化測(cè)試、增加彈性功能等,本文介紹Spring Boot 4 與 Spring Framework 7新特性、升級(jí)要點(diǎn)與實(shí)戰(zhàn)指南,感興趣的朋友跟隨小編一起看看吧
    2026-03-03
  • Java截取特定兩個(gè)標(biāo)記之間的字符串實(shí)例

    Java截取特定兩個(gè)標(biāo)記之間的字符串實(shí)例

    下面小編就為大家?guī)?lái)一篇Java截取特定兩個(gè)標(biāo)記之間的字符串實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-03-03
  • 帶你快速搞定java多線程(2)

    帶你快速搞定java多線程(2)

    這篇文章主要介紹了java多線程編程實(shí)例,分享了幾則多線程的實(shí)例代碼,具有一定參考價(jià)值,加深多線程編程的理解還是很有幫助的,需要的朋友可以參考下
    2021-07-07
  • JavaEE多線程中阻塞隊(duì)列的項(xiàng)目實(shí)踐

    JavaEE多線程中阻塞隊(duì)列的項(xiàng)目實(shí)踐

    本文主要介紹了JavaEE多線程中阻塞隊(duì)列的項(xiàng)目實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-09-09
  • JAVA?拷貝文件的幾種方式小結(jié)

    JAVA?拷貝文件的幾種方式小結(jié)

    本文主要介紹了JAVA拷貝文件的幾種方式,包含普通拷貝,mmap內(nèi)存映射的方式拷貝,零拷貝sendFile方式實(shí)現(xiàn)和多線程的方式實(shí)現(xiàn)拷貝,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • SpringBoot使用validation做參數(shù)校驗(yàn)說(shuō)明

    SpringBoot使用validation做參數(shù)校驗(yàn)說(shuō)明

    這篇文章主要介紹了SpringBoot使用validation做參數(shù)校驗(yàn)說(shuō)明,首先通過(guò)添加hibernate-validator展開(kāi)全文內(nèi)容,具有一定的參考價(jià)值,需要的小伙伴可以參考與喜愛(ài)
    2022-04-04
  • 深入理解JDK26支持Http3屬性

    深入理解JDK26支持Http3屬性

    在JDK 26中,HTTP/3已作為標(biāo)準(zhǔn)特性支持,簡(jiǎn)化HTTP3請(qǐng)求發(fā)起過(guò)程,直接利用java.net.http包實(shí)現(xiàn)高效網(wǎng)絡(luò)通信,下面就來(lái)詳細(xì)的介紹一下
    2026-05-05
  • Mybatis多參數(shù)及實(shí)體對(duì)象傳遞實(shí)例講解

    Mybatis多參數(shù)及實(shí)體對(duì)象傳遞實(shí)例講解

    在使用Mybatis的時(shí)候,經(jīng)常會(huì)有各種各樣的參數(shù)傳遞,不同類型,不同個(gè)數(shù)的參數(shù),下面小編通過(guò)例子給大家講解下Mybatis多參數(shù)及實(shí)體對(duì)象傳遞,一起看看吧
    2016-12-12
  • 使用maven構(gòu)建java9 service實(shí)例詳解

    使用maven構(gòu)建java9 service實(shí)例詳解

    本篇文章主要介紹了使用maven構(gòu)建java9 service實(shí)例詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • java 打造阻塞式線程池的實(shí)例詳解

    java 打造阻塞式線程池的實(shí)例詳解

    這篇文章主要介紹了java 打造阻塞式線程池的實(shí)例詳解的相關(guān)資料,這里提供實(shí)例幫助大家,理解這部分知識(shí),需要的朋友可以參考下
    2017-07-07

最新評(píng)論

南和县| 宁武县| 白城市| 紫金县| 丹阳市| 隆昌县| 丹凤县| 军事| 古浪县| 上栗县| 达拉特旗| 虞城县| 仁怀市| 特克斯县| 乌兰察布市| 繁峙县| 灌阳县| 临邑县| 古浪县| 陇南市| 丰镇市| 汕头市| 富锦市| 吉安市| 珲春市| 荆州市| 吉水县| 厦门市| 祁门县| 梁山县| 怀集县| 上犹县| 武平县| 泰顺县| 莆田市| 吉木乃县| 兴安县| 寿阳县| 津南区| 寿光市| 辽宁省|