使用注释AOP实现接口访问次数限制

简介: 使用注释AOP实现接口访问次数限制

前言


在日常开发工作中,我们常有接口会暴露出来,虽然我们增加了各种检验和拦截可以拦截大多数恶意访问,但是你不能保证对接方的猿子不会造出一个死循环来访问你的接口,尤其是我们的程序作为一个平台使用的时候,别人的一个误操作可能会造成服务器宕机,到时候成千上万的客户都会受到影响,所以在这种对接过程中一定要对对方的接口访问次数进行限制!这种方式可以理解为微服务中的服务降级!


安排栗子


新建一个注释类:


@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LimitTime {
  // 访问次数,默认为10次
  int time() default 10;
  // 过期时间,时间戳间隔
  long timeout() default 1;
}


定义一个存放调用信息的DTO:


@Data
public class LimitDTO {
    //最近一次刷新时间戳
  private Long refreshTime;
  //剩余访问次数
  private Integer time;
}

新建一个切面类:

注意在存储访问状态对象的时候一定要使用ConcurrentHashMap,此为线程安全的map,支持并发访问!

@Component
@Order
@Aspect
public class LimitTimeAspect {
  private ConcurrentHashMap<String, LimitDTO> limitMap = new ConcurrentHashMap<>();
  @Pointcut("@annotation(limitTime)")
  public void limit(LimitTime limitTime) {
  }
  @Around("limit(limitTime)")
  public Object aroundLog(ProceedingJoinPoint joinpoint, LimitTime limitTime) throws Throwable {
      //获取传入的最大访问次数
    int time= limitKey.time();
    //获取计算时间
    long timeout = limitKey.timeout();
    //获取访问方法
    Object target = joinpoint.getTarget().getClass().getName();
    String key= target.toString();
    //如果第一次访问该方法
    if (limitMap.get(key) == null) {
        //新建一次对象存放访问信息
      LimitDTO limitDTO=new LimitDTO();
      limitDTO.setTime(time- 1);
      limitDTO.setRefreshTime(new Date().getTime());
      limitMap.put(key, limitDTO);
    }else {
        //如果不是第一次访问,获取上次访问的信息
      LimitDTO limitDTO=limitMap.get(key);
      //如果和上次刷新时间比已经过期
      if (new Date().getTime() - limitDTO.getRefreshTime() > timeout) {
          //将对象中的刷新时间和访问次数刷新
        limitDTO.setRefreshTime(new Date().getTime());
        limitDTO.setTime(time);
        limitMap.put(key, limitDTO);
      }
      //获取当前访问对象中的剩余访问次数
      int t = (int) limitMap.get(key).getTime;
      //如果访问次数大于0
      if (t > 0) {
          //允许访问,并将访问次数-1
        limitDTO.setTime(--t);
      } else {
          //如果已经没有访问次数,返回错误信息
        ResultBO<Object> resultBO = new ResultBO<>();
        resultBO.setCode(1);
        resultBO.setMsg("已达最大访问次数");
        return resultBO;
      }
    }
    //打印信息
    System.err.println("剩余次数:" + limitMap.get(key).getTime + " 方法名称:" + key);
    return joinpoint.proceed();
  }

使用该注释:

@RequestMapping(value = "/sendCmd", method = RequestMethod.POST)
@ResponseBody
@LimitKey(time= 10, timeout = 10000)//10秒内可以访问10次
public int sendCmd(@RequestBody List<CmdDO> cmds) {
  //do something
  return new ResultBO<>();
}


测试:

image.png

image.png

撒花!完成!

相关文章
|
3月前
|
存储 JSON Java
SpringBoot集成AOP实现每个接口请求参数和返回参数并记录每个接口请求时间
SpringBoot集成AOP实现每个接口请求参数和返回参数并记录每个接口请求时间
124 2
|
3月前
|
缓存 Java Sentinel
Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截
Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截
|
3月前
|
Java
Springboot 使用自定义注解结合AOP方式校验接口参数
Springboot 使用自定义注解结合AOP方式校验接口参数
Springboot 使用自定义注解结合AOP方式校验接口参数
|
3月前
|
Java Spring
Spring5源码(28)-Aop知识点回顾以及基于Advice接口的增强实现
Spring5源码(28)-Aop知识点回顾以及基于Advice接口的增强实现
39 0
|
Java Spring
2021-08-09构造方法注入,项目搭建,通过注释注入,注解扫描器,spring,ioc结束,AOP(二)
2021-08-09构造方法注入,项目搭建,通过注释注入,注解扫描器,spring,ioc结束,AOP
180 0
|
Java Spring
2021-08-09构造方法注入,项目搭建,通过注释注入,注解扫描器,spring,ioc结束,AOP(一)
2021-08-09构造方法注入,项目搭建,通过注释注入,注解扫描器,spring,ioc结束,AOP
177 0
|
Java Spring
利用 AOP 记录接口日志
利用 AOP 记录接口日志
133 0
Spring-AOP @AspectJ进阶之访问连接点信息
Spring-AOP @AspectJ进阶之访问连接点信息
65 0
|
SQL NoSQL 前端开发
SpringBoot自定义注解+AOP+redis实现防接口幂等性重复提交,从概念到实战
SpringBoot自定义注解+AOP+redis实现防接口幂等性重复提交,从概念到实战
993 2
SpringBoot自定义注解+AOP+redis实现防接口幂等性重复提交,从概念到实战
|
SQL Java 数据库连接
注解方式实现AOP的接口控制
注解方式实现AOP的接口控制
注解方式实现AOP的接口控制