亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

使用AOP來實現接口請求頻率限制

標簽:
Java

老规矩,定义一个注解:

/*
* 被该注解修饰的方法都会被切面拦截进行请求次数限制
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Limit {
   int maxRequestPerMinute();
}

我们在想要进行频率限制的方法上添加注解:

@RequestMapping("/")
   @Limit(maxRequestPerMinute = 10)
   public String index(){
       return "index.html";
   }

定义一个切面,代码如下(代码很长,可以跳到最后看分析):

/**
* @author my
*/
@Aspect
@Component
@Order(1)
public class RequestLimitAspect {

   public static final String REQUEST_LIMIT = "requestLimit";
   public static final int MINTUE = 60000;

   @Pointcut("@annotation(wang.ismy.zbq.annotations.Limit)")
   public void pointCut() {
   }

   @Before("pointCut()")
   public void before(JoinPoint joinPoint) {
       var session = getCurrentUserSession();

       Signature signature = joinPoint.getSignature();
       MethodSignature methodSignature = (MethodSignature) signature;
       Method method = methodSignature.getMethod();
       var a = method.getAnnotation(Limit.class);

       if (session == null) {
           ErrorUtils.error(R.UNKNOWN_ERROR);
       }

       if (session.getAttribute(REQUEST_LIMIT) == null) {
           Map<String, RequestLimitDTO> map = new HashMap<>();
           session.setAttribute(REQUEST_LIMIT, map);
       }
       Map<String, RequestLimitDTO> map = (Map<String, RequestLimitDTO>) session.getAttribute(REQUEST_LIMIT);

       String methodName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();

       if (map.get(methodName) == null) {
           RequestLimitDTO dto = new RequestLimitDTO();
           dto.setLastRequestTime(System.currentTimeMillis());
           dto.setRequestCount(0);
           map.put(methodName, dto);
       } else {
           RequestLimitDTO dto = map.get(methodName);
           // 如果当前请求距离上一次请求时间间隔大于60s,则清空计数器
           if (System.currentTimeMillis()-dto.getLastRequestTime() >= MINTUE) {
               dto.setRequestCount(0);
           }

           dto.increaseCount();
           // 如果当前请求计数器的大于设定的阈值,则拒绝此次请求
           if (dto.getRequestCount() > a.maxRequestPerMinute()) {
               ErrorUtils.error(R.REQUEST_FREQUENTLY);
           }

           dto.setLastRequestTime(System.currentTimeMillis());


       }


   }

   private HttpSession getCurrentUserSession() {
       HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
       return request.getSession();
   }
}

那么,在这里谈谈这个频率限制的大概实现:

首先,被注解修饰的方法都会经过这个前置通知:

    1)获取该切面的方法全名。

    2)从session当中通过这个方法全名获取对应的请求dto(dto使用哈希表与方法全名进行映射):

 * @author my
*/
@Data
public class RequestLimitDTO {

   private Integer requestCount;

   private Long lastRequestTime;

   public synchronized void increaseCount(){
       requestCount++;
   }

   public synchronized void setRequestCount(Integer requestCount) {
       this.requestCount = requestCount;
   }
}

    那么重点来了:

    算法的核心是这段:

if (map.get(methodName) == null) {
   RequestLimitDTO dto = new RequestLimitDTO();
   dto.setLastRequestTime(System.currentTimeMillis());
   dto.setRequestCount(0);
   map.put(methodName, dto);
} else {
   RequestLimitDTO dto = map.get(methodName);
   // 如果当前请求距离上一次请求时间间隔大于60s,则清空计数器
   if (System.currentTimeMillis()-dto.getLastRequestTime() >= MINTUE) {
       dto.setRequestCount(0);
   }

   dto.increaseCount();
   // 如果当前请求计数器的大于设定的阈值,则拒绝此次请求
   if (dto.getRequestCount() > a.maxRequestPerMinute()) {
       ErrorUtils.error(R.REQUEST_FREQUENTLY);
   }

   dto.setLastRequestTime(System.currentTimeMillis());
}

        这段代码没有什么特别的地方,只是要注意的是increase和setRequestCount方法都要被synchronized关键字修饰,避免在并发的情况下出现数据不一致。

 最后,不可否认,为了快速实现这个功能,这段代码写的很烂,很多地方实现得都不优美。

比如

if (System.currentTimeMillis()-dto.getLastRequestTime() >= MINTUE) {

这里的MINUTE常量可以让客户端程序员自行指定 ,这样就能拥有更多的灵活性。


點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消