自定义限制接口访问次数(ExpiringMap)

2023-11-01

ExpiringMap简介:

它具有高性能、低开销、零依赖、线程安全、使用ConcurrentMa的实现过期entries等优点。主要特点包括:过期策略、可变有效期、最大尺寸、侦听器过期、延迟输入加载、过期自省。
可设置Map中的Entry在一段时间后自动过期,key过期 value同时会过期。
可设置Map最大容纳值,当到达Maximum size后,再次插入值会导致Map中的第一个值过期。
可添加监听事件,在监听到Entry过期时调度监听函数。
可以设置懒加载,在调用get()方法时创建对象。
可以设置过期策略:
ExpirationPolicy.CREATED:在每次更新元素时,过期时间同时清零。
ExpirationPolicy.ACCESSED:在每次访问元素时,过期时间同时清零。

  • 添加依赖

dependency>
   <groupId>net.jodah</groupId>
   <artifactId>expiringmap</artifactId>
   <version>0.5.10</version>
</dependency>
  • 自定义注解

package cn.infinitefun.platform.model.annotations;

import java.lang.annotation.*;

/**
 * @author zhangjinlong
 * 控制接口访问次数
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LimitRequest {
    /**
     * 持续时间  分钟,可自行修改时间格式
     */
    long time() default 60;

    /**
     * 持续时间内最大请求次数
     */
    int count() default Integer.MAX_VALUE;
}
  • 自定义切面AOP

package cn.infinitefun.platform.config;

import cn.infinitefun.platform.model.annotations.LimitRequest;
import cn.infinitefun.platform.model.dto.ResultInfo;
import lombok.extern.slf4j.Slf4j;
import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
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.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author zhangjinlong
 * 限制接口访问次数
 */
@Aspect
@Component
@Slf4j
public class LimitRequestAspect {

    /**
     * 可设置ExpiringMap中的Entry在一段时间后自动过期,key过期 value同时会过期。
     * 可设置Map最大容纳值,当到达Maximum size后,再次插入值会导致Map中的第一个值过期。
     * 可添加监听事件,在监听到Entry过期时调度监听函数。
     * 可以设置懒加载,在调用get()方法时创建对象。
     * 可以设置过期策略:
     * ExpirationPolicy.CREATED:在每次更新元素时,过期时间同时清零。
     * ExpirationPolicy.ACCESSED:在每次访问元素时,过期时间同时清零.
     */

    private static ConcurrentHashMap<String, ExpiringMap<String, Integer>> hashMap = new ConcurrentHashMap<>();

    @Pointcut("@annotation(limitRequest)")
    public void excudeService(LimitRequest limitRequest) {
    }

    /**
     * @param pjp          接收参数
     * @param limitRequest 过期时间和最大访问次数
     * @return
     * @throws Throwable
     */
    @Around("excudeService(limitRequest)")
    public Object doAround(ProceedingJoinPoint pjp, LimitRequest limitRequest) throws Throwable {
        Object arg1 = pjp.getArgs()[0];
        /**
         * 只对无参数进行接口限制访问次数
         */
        if (ObjectUtils.isEmpty(arg1)) {
            RequestAttributes ra = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes sra = (ServletRequestAttributes) ra;
            HttpServletRequest request = sra.getRequest();
            ExpiringMap<String, Integer> map = hashMap.getOrDefault(request.getRequestURI(), ExpiringMap.builder().variableExpiration().build());
            Integer count = map.getOrDefault(request.getRemoteAddr(), 0);
            if (count >= limitRequest.count()) {
                return ResultInfo.error("同步导出全部次数超过限制, 稍等" + limitRequest.time() + "分钟");
            } else if (count == 0) {
                /**
                 * map.put(
                 * key, value , ExpirationPolicy(过期策略),duration(持续时间), TimeUnit(时间格式: 日、时、分、秒、毫秒)
                 * )
                 */
                map.put(request.getRemoteAddr(), count + 1, ExpirationPolicy.CREATED, limitRequest.time(), TimeUnit.MINUTES);
            } else {
                map.put(request.getRemoteAddr(), count + 1);
            }
            hashMap.put(request.getRequestURI(), map);
        }
        Object result = pjp.proceed();
        return result;
    }
}

ConcurrentHashMap是多线程安全的Map,它的key是接口url,value是一个多线程安全且键值对是有有效期的Map(ExpiringMap)。

ExpiringMap的key是请求的ip地址,value是已经请求的次数

  • 示例(注解加在方法上即可)

@ApiOperation("服务")
    @PostMapping("/task")
    @LimitRequest(time = 30 ,count = 1)
    public ResultInfo<?> invokeImportService(@RequestBody List<String> nameList){
        try {
            this.service.service(nameList);
            return ResultInfo.ok("正在同步");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultInfo.error("同步失败");
        }
    }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自定义限制接口访问次数(ExpiringMap) 的相关文章

随机推荐

  • 6、numpy——高级索引

    NumPy 比一般的 Python 序列提供更多的索引方式 除了之前看到的用整数和切片的索引外 数组可以由整数数组索引 布尔索引及花式索引 1 整数数组索引 1 1 以下实例获取数组中 0 0 1 1 和 2 0 位置处的元素 1 impo
  • 还在为英语学习发愁吗?身为程序员的你可能需要这样一份“宝典”(上) ...

    雷锋网 AI 科技评论按 本文作者于江水 这是他在 GitHub 上发布的一篇文章 以下是他的原文 主要包括以下几个部分 本指南的内容概要和目标人群 语言学习的本质浅析 如何构建一个识别英语的程序 我的训练方法 常见问题 QA 资料 工具推
  • 【Python百日进阶-Web开发-Peewee】Day278 - SQLite 扩展(三)

    文章目录 12 2 7 class JSONPath 12 2 8 class SearchField 12 2 9 class FTS5Model 12 2 7 class JSONPath class JSONPath field pa
  • 2018年最新桌面CPU性能排行天梯图(含至强处理器)

    排名 处理器 图例 分数 1 Intel Xeon Platinum 8173M 2 00GHz 28860 2 Intel Xeon Gold 6154 3 00GHz 27789 3 Intel Core i9 7980XE 2 60G
  • Eclipse 中Deployment Assembly 无法正常显示

    我将本地Maven Java项目转换为Web项目 应该能够在Eclipse gt 转化项目名 gt properties 看到看到Deployment Assembly出现 如果还是没有该选项 很有可能在Eclipse中Deployment
  • python进阶:python高级编程技巧(上)

    1 深入类和对象 1 1鸭子类型和多态 鸭子类型多态的概念是应用于Java和C 这一类强类型语言中 而Python崇尚 鸭子类型 动态语言调用实例方法时不检查类型 只要方法存在 参数正确 就可以调用 这就是动态语言的 鸭子类型 它并不要求严
  • Jenkins自动构建部署项目(springboot+maven+svn)jar包启动方式(java -jar 包.jar)

    我的环境 linux centos6 5 jdk1 8 maven3 5 svn 第一步 安装必要插件 Deploy to container Plugin 部署到容器插件 Publish Over SSH 通过SSH发送构建构件 Buil
  • Hadoop学习——简单介绍及单点配置步骤(2018012-10补充)

    Hadoop介绍 Hadoop是一个开源的 可靠的 可扩展的系统架构 可利用分布式架构来存储海量数据 以及实现分布式的计算 Doug Cutting是创始人 同时也联合开发了Lucence Nutch Hadoop作用简概 存储海量数据 计
  • windows系统怎么用注册表修改桌面文件路径

    方法 步骤 1 调出运行窗口 输入regedit命令后回车打开注册表 2 在打开的注册表界面中依次展开以下路径 如图所示 HKEY CURRENT USER Software Microsoft Windows CurrentVersion
  • 【模型压缩】网络层与算子融合

    由于深度学习网络层数深 结构复杂 生成的算子数量众多 带了巨大的计算资源在和时间的消耗 业界对于加速算子的计算展开了一定研究 比较经典的方法是将多个算子重新组合成一个新的算子 同时对生成的代码进行底层的性能优化 融合成新算子后计算相对于多个
  • 字节的测试面试题,你觉得很难吗?不是有手就行....

    年前的时候 我的一个粉丝跟我说 他在面试美团的自动化测试岗的时候 不幸挂掉了 越想越可惜 回想面试经过 好好总结了几个点 发现面试没过的主要原因是在几个关键的问题没有给到面试官想要的答案 字节的面试会问些什么问题呢 他给我的留言是这样的 根
  • QT调用第三方dll (Lib方式)

    在项目的 pro文件中 增加一句 LIBS L D qtsrc myproject lmydll 在 cpp文件中 声明mydll dll里面导出的函数 extern C int add int a int b int subtract i
  • PYTHON实现自动发送邮件(QQ,163,139三种邮箱演示)

    测试文件与代码结构 一 QQ邮箱发送邮件 大致步骤 1 登录qq邮箱 选择设置 2 点击账户 进入设置界面 3 授权 生成授权码 4 编写发送代码 密码使用的是授权生成的代码 保证发送邮箱的SMTP功能是开启的 5 效果展示 发送代码 1
  • jupyter中图片显示

    文章目录 jupyter notebook中图片显示 1 html方式 2 PIL图片显示 3 opencv图片显示 4 Ipython 方式 jupyter notebook中图片显示 以下用多种方式 其中第一种和第四种方便查看图片 代码
  • chmod命令原理及用法详解

    Chmod命令主要用于修改 设置文件权限 chmod 修改文件权限主要有两种方式 字母法与数字法 虽然数字法相对字母法简单 但是数字法是基于字母法 所以这里先介绍字母法 1 字母法 chmod u g o a r w x 文件名 以上是ch
  • Linux-应用编程-学习总结(3):进程间通信(上)

    Linux 应用编程 学习总结 3 进程间通信 上 前言 进程间通信相关概念 管道 管道的概念 管道的原理 管道的局限性 创建匿名管道 fifo 有名管道 特点 使用场景 创建方式 内存映射区 前言 这次对进程间通信进行总结 上一篇文章以及
  • 微信开放平台【第三方平台】java开发总结:预授权码(pre_auth_code)(三)

    微信第三方平台预授权码 pre auth code 开发说明 全网最详细的微信第三方平台预授权码开发说明 预授权码 预授权码 pre auth code 是第三方平台方实现授权托管的必备信息 每个预授权码有效期为 10 分钟 需要先获取令牌
  • XMPP客户端库Smack 4.1.4版官方开发文档之二

    本文转载自 博客主页 http blog csdn net chszs 三 Smack库的组成 Smack库可以内嵌到任意的Java应用程序中 Smack库有数个JAR文件组成 非常具有灵活性 1 smack core jar 提供了核心X
  • 这是mybatis最简单的入门

    这里有一个demo 这是mybatis最简单的入门 使用的IDE为idea 是maven的哦 这篇只是很简单的一个查询demo 目标是ssm 先来pom文件 这个不知道在网上哪里找的 lt gt
  • 自定义限制接口访问次数(ExpiringMap)

    ExpiringMap简介 它具有高性能 低开销 零依赖 线程安全 使用ConcurrentMa的实现过期entries等优点 主要特点包括 过期策略 可变有效期 最大尺寸 侦听器过期 延迟输入加载 过期自省 可设置Map中的Entry在一