Springboot Redis Lua 分布式限流器

pom文件中添加如下依賴包,比較關鍵的就是 spring-boot-starter-data-redisspring-boot-starter-aop

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

RedisTemplate

@Configuration
public class RedisLimiterHelper {@Beanpublic RedisTemplate<String, Serializable> limitRedisTemplate(LettuceConnectionFactory redisConnectionFactory) {RedisTemplate<String, Serializable> template = new RedisTemplate<>();template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(new GenericJackson2JsonRedisSerializer());template.setConnectionFactory(redisConnectionFactory);return template;}
}

限流類型枚舉類

/*** @author fu* @description 限流類型* @date 2020/4/8 13:47*/
public enum LimitType {/*** 自定義key*/CUSTOMER,/*** 請求者IP*/IP;
}

自定義注解

/*** @author fu* @description 自定義限流注解* @date 2020/4/8 13:15*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Limit {/*** 名字*/String name() default "";/*** key*/String key() default "";/*** Key的前綴*/String prefix() default "";/*** 給定的時間范圍 單位(秒)*/int period();/*** 一定時間內最多訪問次數*/int count();/*** 限流的類型(用戶自定義key 或者 請求ip)*/LimitType limitType() default LimitType.CUSTOMER;
}

切面代碼實現

/*** @author fu* @description 限流切面實現* @date 2020/4/8 13:04*/
@Aspect
@Configuration
public class LimitInterceptor {private static final Logger logger = LoggerFactory.getLogger(LimitInterceptor.class);private static final String UNKNOWN = "unknown";private final RedisTemplate<String, Serializable> limitRedisTemplate;@Autowiredpublic LimitInterceptor(RedisTemplate<String, Serializable> limitRedisTemplate) {this.limitRedisTemplate = limitRedisTemplate;}/*** @param pjp* @author fu* @description 切面* @date 2020/4/8 13:04*/@Around("execution(public * *(..)) && @annotation(com.xiaofu.limit.api.Limit)")public Object interceptor(ProceedingJoinPoint pjp) {MethodSignature signature = (MethodSignature) pjp.getSignature();Method method = signature.getMethod();Limit limitAnnotation = method.getAnnotation(Limit.class);LimitType limitType = limitAnnotation.limitType();String name = limitAnnotation.name();String key;int limitPeriod = limitAnnotation.period();int limitCount = limitAnnotation.count();/*** 根據限流類型獲取不同的key ,如果不傳我們會以方法名作為key*/switch (limitType) {case IP:key = getIpAddress();break;case CUSTOMER:key = limitAnnotation.key();break;default:key = StringUtils.upperCase(method.getName());}ImmutableList<String> keys = ImmutableList.of(StringUtils.join(limitAnnotation.prefix(), key));try {String luaScript = buildLuaScript();RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class);Number count = limitRedisTemplate.execute(redisScript, keys, limitCount, limitPeriod);logger.info("Access try count is {} for name={} and key = {}", count, name, key);if (count != null && count.intValue() <= limitCount) {return pjp.proceed();} else {throw new RuntimeException("You have been dragged into the blacklist");}} catch (Throwable e) {if (e instanceof RuntimeException) {throw new RuntimeException(e.getLocalizedMessage());}throw new RuntimeException("server exception");}}/*** @author fu* @description 編寫 redis Lua 限流腳本* @date 2020/4/8 13:24*/public String buildLuaScript() {StringBuilder lua = new StringBuilder();lua.append("local c");lua.append("\nc = redis.call('get',KEYS[1])");// 調用不超過最大值,則直接返回lua.append("\nif c and tonumber(c) > tonumber(ARGV[1]) then");lua.append("\nreturn c;");lua.append("\nend");// 執行計算器自加lua.append("\nc = redis.call('incr',KEYS[1])");lua.append("\nif tonumber(c) == 1 then");// 從第一次調用開始限流,設置對應鍵值的過期lua.append("\nredis.call('expire',KEYS[1],ARGV[2])");lua.append("\nend");lua.append("\nreturn c;");return lua.toString();}/*** @author fu* @description 獲取id地址* @date 2020/4/8 13:24*/public String getIpAddress() {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return ip;}
}

控制層實現

/*** @Author: fu* @Description:*/
@RestController
public class LimiterController {private static final AtomicInteger ATOMIC_INTEGER_1 = new AtomicInteger();private static final AtomicInteger ATOMIC_INTEGER_2 = new AtomicInteger();private static final AtomicInteger ATOMIC_INTEGER_3 = new AtomicInteger();/*** @author fu* @description* @date 2020/4/8 13:42*/@Limit(key = "limitTest", period = 10, count = 3)@GetMapping("/limitTest1")public int testLimiter1() {return ATOMIC_INTEGER_1.incrementAndGet();}/*** @author fu* @description* @date 2020/4/8 13:42*/@Limit(key = "customer_limit_test", period = 10, count = 3, limitType = LimitType.CUSTOMER)@GetMapping("/limitTest2")public int testLimiter2() {return ATOMIC_INTEGER_2.incrementAndGet();}/*** @author fu* @description * @date 2020/4/8 13:42*/@Limit(key = "ip_limit_test", period = 10, count = 3, limitType = LimitType.IP)@GetMapping("/limitTest3")public int testLimiter3() {return ATOMIC_INTEGER_3.incrementAndGet();}}

原作者:https://mp.weixin.qq.com/s/kyFAWH3mVNJvurQDt4vchA

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/213876.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/213876.shtml
英文地址,請注明出處:http://en.pswp.cn/news/213876.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于ssm實驗室開放管理系統論文

摘 要 現代經濟快節奏發展以及不斷完善升級的信息化技術&#xff0c;讓傳統數據信息的管理升級為軟件存儲&#xff0c;歸納&#xff0c;集中處理數據信息的管理方式。本實驗室開放管理系統就是在這樣的大環境下誕生&#xff0c;其可以幫助管理者在短時間內處理完畢龐大的數據信…

高效純化樹脂A-2313 CPR

在化工、制藥等行業中&#xff0c;對colorful chemicals的純化一直是挑戰。本文將為您介紹一款具有卓越性能的強堿性陰離子交換樹脂——Tulsion A-2313 CPR。通過分析其特性和應用&#xff0c;展示其在colorful chemicals純化領域的優勢。 一、Tulsion A-2313 CPR離子交換樹脂的…

代碼隨想錄二刷 |二叉樹 |94.二叉樹的中序遍歷

代碼隨想錄二刷 &#xff5c;二叉樹 &#xff5c;二叉樹的中序遍歷 題目描述解題思路代碼實現迭代法遞歸法 題目描述 94.二叉樹的中序遍歷 給定一個二叉樹的根節點 root &#xff0c;返回 它的 中序 遍歷 。 示例 1&#xff1a; 輸入&#xff1a;root [1,null,2,3] 輸出&a…

漏洞復現-浙江宇視 isc LogReport.php 遠程命令執行漏洞(附漏洞檢測腳本)

免責聲明 文章中涉及的漏洞均已修復&#xff0c;敏感信息均已做打碼處理&#xff0c;文章僅做經驗分享用途&#xff0c;切勿當真&#xff0c;未授權的攻擊屬于非法行為&#xff01;文章中敏感信息均已做多層打馬處理。傳播、利用本文章所提供的信息而造成的任何直接或者間接的…

C++臨時對象生命周期

引言 朋友問了我一段代碼&#xff1a; const string & foo(const string & a, const string & b) {return a.empty() ? b : a; } int main () {auto & s foo("", "foo"); // auto is const stringcout << s << \n;return …

第二百回 如何獲取App自身的信息

文章目錄 1. 概念介紹2. 使用方法2.1 ClipOval2.2 ClipRRect 3. 示例代碼 我們在上一章回中介紹了AspectRatio Widget相關的內容&#xff0c;本章回中將介紹剪裁類組件(Clip).閑話休提&#xff0c;讓我們一起Talk Flutter吧。 1. 概念介紹 我們在這里說的剪裁類組件主要是指對…

dockerfile---創建鏡像

dockerfile創建鏡像&#xff1a;創建自定義鏡像。 包擴配置文件的創建&#xff0c;掛載點&#xff0c;對外暴露的端口。設置環境變量。 docker鏡像的方式: 1、基于官方源進行創建 根據官方提供的鏡像源&#xff0c;創建鏡像&#xff0c;然后拉起容器。是一個白板&#xff0c…

初識人工智能,一文讀懂強化學習的知識文集(5)

&#x1f3c6;作者簡介&#xff0c;普修羅雙戰士&#xff0c;一直追求不斷學習和成長&#xff0c;在技術的道路上持續探索和實踐。 &#x1f3c6;多年互聯網行業從業經驗&#xff0c;歷任核心研發工程師&#xff0c;項目技術負責人。 &#x1f389;歡迎 &#x1f44d;點贊?評論…

2023年運營級網賺網盤平臺搭建指南(包含源碼和教程)

源碼介紹 為什么要考慮自己搭建網盤呢&#xff1f;現如今&#xff0c;許多大型網盤平臺都對文件添加了各種限制&#xff0c;導致很多文件容易被刪除。而且&#xff0c;大部分網盤還會限制下載速度&#xff0c;如果沒有開通VIP會員&#xff0c;使用起來非常不便。 本指南提供了…

免費節假日api接口使用教程-聚合數據

免費節假日api接口使用教程-聚合數據 文章目錄 &#x1f4d6;訪問官網&#x1f330;例子完整代碼&#x1f58a;?最后總結 &#x1f4d6;訪問官網 聚合數據 官網地址 https://dashboard.juhe.cn/home 點擊api 接口文檔 &#x1f330;例子 get方式 curl -k -i -d “key您申請…

解決Git提交錯誤分支

如果 Git 提交到錯誤的分支&#xff0c;可以通過以下步驟將其轉移到正確的分支上&#xff1a; 1.檢查當前所在的分支&#xff0c;可以通過 git branch 命令查看。 git branch2.切換到正確的分支&#xff0c;可以通過 git checkout <正確的分支名> 命令進行切換。 git …

vue使用echarts顯示中國地圖

項目引入echarts以后&#xff0c;在頁面創建canvas標簽 引入一個公共js文件&#xff08;下面這段代碼就是china.js文件&#xff09; (function (root, factory) {if (typeof define function && define.amd) {// AMD. Register as an anonymous module.define([ex…

【EXCEL】折線圖添加垂直x軸的豎線|畫圖

相關鏈接&#xff1a;excel 添加垂直豎向直線 如何在Excel中添加水平和垂直線&#xff1f; 因為加輔助列有點不習慣&#xff0c;已經有分位數橫坐標了&#xff0c;想著試下用散點圖的誤差線畫 效果圖&#xff1a; 步驟&#xff1a; s1&#xff1a;隨便框選兩列數據–>插入(…

大創項目推薦 卷積神經網絡手寫字符識別 - 深度學習

文章目錄 0 前言1 簡介2 LeNet-5 模型的介紹2.1 結構解析2.2 C1層2.3 S2層S2層和C3層連接 2.4 F6與C5層 3 寫數字識別算法模型的構建3.1 輸入層設計3.2 激活函數的選取3.3 卷積層設計3.4 降采樣層3.5 輸出層設計 4 網絡模型的總體結構5 部分實現代碼6 在線手寫識別7 最后 0 前言…

深入理解JavaScript異步編程與Promise

異步編程的背景 在Web開發中&#xff0c;異步編程是為了解決JavaScript的單線程執行模型導致的阻塞問題。異步編程允許程序在等待某些操作完成的同時&#xff0c;繼續執行其他任務&#xff0c;提高了程序的效率和響應速度。 回調地獄與Promise的誕生 回調地獄是異步編程中一…

Unity中實現ShaderToy卡通火(一)

文章目錄 前言一、準備好我們的后處理基礎腳本1、C#&#xff1a;2、Shader&#xff1a; 二、開始逐語句對ShaderToy進行轉化1、首先&#xff0c;找到我們的主函數 mainImage2、其余的方法全部都是在 mainImage 函數中調用的方法3、替換后的代碼(已經沒報錯了&#xff0c;都是效…

智能優化算法應用:基于正余弦算法3D無線傳感器網絡(WSN)覆蓋優化 - 附代碼

智能優化算法應用&#xff1a;基于正余弦算法3D無線傳感器網絡(WSN)覆蓋優化 - 附代碼 文章目錄 智能優化算法應用&#xff1a;基于正余弦算法3D無線傳感器網絡(WSN)覆蓋優化 - 附代碼1.無線傳感網絡節點模型2.覆蓋數學模型及分析3.正余弦算法4.實驗參數設定5.算法結果6.參考文…

基于單個參數線性回歸的機器學習代碼

本文為學習吳恩達版本機器學習教程的代碼整理&#xff0c;使用的數據集為https://github.com/fengdu78/Coursera-ML-AndrewNg-Notes/blob/f2757f85b99a2b800f4c2e3e9ea967d9e17dfbd8/code/ex1-linear%20regression/ex1data1.txt 將數據集和py代碼放到同一目錄中&#xff0c;使…

2023最新八股文前端面試題

第一章 Css 1.說一下CSS的盒模型。 在HTML頁面中的所有元素都可以看成是一個盒子盒子的組成:內容content、內邊距padding、邊框border、外邊距margin盒模型的類型: 標準盒模型 margin border padding content IE盒模型 margin content(border padding) 控制盒模型的模式…

淘寶api接口測試方式(item_get-獲得淘寶商品詳情)

注冊淘寶開放平臺賬號&#xff1a;首先&#xff0c;你需要在淘寶開放平臺上注冊一個賬號&#xff0c;并創建一個應用。獲取App Key和Secret Key&#xff1a;在創建應用后&#xff0c;你會獲得App Key和Secret Key&#xff0c;這些憑證將用于調用API。了解淘寶商品詳情接口&…