蚂蚁课堂:自定义注解方式封装RateLimiter 限流

 

 1先自定义注解

@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtRateLimiter {
    double value();

    long timeOut();
}

 2 整合aop

 

  1 /**
  2  * 功能说明:
  3  * 功能作者:
  4  * 创建日期:
  5  * 版权归属:每特教育|蚂蚁课堂所有 www.itmayiedu.com
  6  */
  7 package com.itmayiedu.aop;
  8 
  9 import java.io.IOException;
 10 import java.io.PrintWriter;
 11 import java.lang.reflect.Method;
 12 import java.util.Map;
 13 import java.util.concurrent.ConcurrentHashMap;
 14 import java.util.concurrent.TimeUnit;
 15 
 16 import javax.servlet.http.HttpServletRequest;
 17 import javax.servlet.http.HttpServletResponse;
 18 
 19 import org.aspectj.lang.ProceedingJoinPoint;
 20 import org.aspectj.lang.annotation.Around;
 21 import org.aspectj.lang.annotation.Aspect;
 22 import org.aspectj.lang.annotation.Pointcut;
 23 import org.aspectj.lang.reflect.MethodSignature;
 24 import org.springframework.stereotype.Component;
 25 import org.springframework.web.context.request.RequestContextHolder;
 26 import org.springframework.web.context.request.ServletRequestAttributes;
 27 
 28 import com.google.common.util.concurrent.RateLimiter;
 29 import com.itmayiedu.annotation.ExtRateLimiter;
 30 
 31 /**
 32  * 功能说明:使用AOP环绕通知判断拦截所有springmvc 请求,判断请求方法上是否存在ExtRateLimiter <br>
 33  * 1.判断请求方法上是否有@ExtRateLimiter<br>
 34  * 2.如果方法上存在@ExtRateLimiter注解话<br>
 35  * 3.使用反射技术获取@ExtRateLimiter注解方法上的参数<br>
 36  * 4.调用原生RateLimiter代码创建令牌桶<br>
 37  * 5.如果获取令牌超时的,直接调用服务降级方法(需要自己定义)<br>
 38  * 6.如果能够获取令牌的话,直接进入实际请求方法。<br>
 39  * AOP创建方式有两种 注解版本和XML方式<br>
 40  * <br>
 41  * 创建作者:每特教育-余胜军<br>
 42  */
 43 @Aspect
 44 @Component
 45 public class RateLimiterAop {
 46     private Map<String, RateLimiter> rateHashMap = new ConcurrentHashMap<>();
 47 
 48     // 定义切入点 拦截com.itmayeidu.api
 49     @Pointcut("execution(public * com.itmayeidu.api.*.*(..))")
 50 
 51     public void rlAop() {
 52     }
 53 
 54     // 使用AOP环绕通知判断拦截所有springmvc 请求,判断请求方法上是否存在ExtRateLimiter注解
 55     @Around("rlAop()")
 56     public Object doBefore(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
 57         // 1.如果请求方法上存在@ExtRateLimiter注解的话
 58         Method sinatureMethod = getSinatureMethod(proceedingJoinPoint);
 59         if (sinatureMethod == null) {
 60             // 直接报错
 61             return null;
 62         }
 63         // 2.使用java的反射机制获取拦截方法上自定义注解的参数
 64         ExtRateLimiter extRateLimiter = sinatureMethod.getDeclaredAnnotation(ExtRateLimiter.class);
 65         if (extRateLimiter == null) {
 66             // 直接进入实际请求方法中
 67             return proceedingJoinPoint.proceed();
 68         }
 69         double permitsPerSecond = extRateLimiter.permitsPerSecond();
 70         long timeout = extRateLimiter.timeout();
 71         // 3.调用原生的RateLimiter创建令牌 保证每个请求对应都是单例的RateLimiter
 72         // /index---RateLimiter /order --RateLimiter 使用hashMap key为 请求的url地址##
 73         // 相同的请求在同一个桶
 74         String requestURI = getRequestURI();
 75         RateLimiter rateLimiter = null;
 76         if (rateHashMap.containsKey(requestURI)) {
 77             // 如果在hashMap URL 能检测到RateLimiter
 78             rateLimiter = rateHashMap.get(requestURI);
 79         } else {
 80             // 如果在hashMap URL 没有检测到RateLimiter 添加新的RateLimiter
 81             rateLimiter = RateLimiter.create(permitsPerSecond);
 82             rateHashMap.put(requestURI, rateLimiter);
 83         }
 84         // 4.获取令牌桶中的令牌,如果没有有效期获取到令牌的话,则直接调用本地服务降级方法,不会进入到实际请求方法中。
 85         boolean tryAcquire = rateLimiter.tryAcquire(timeout, TimeUnit.MILLISECONDS);
 86         if (!tryAcquire) {
 87             // 服务降级
 88             fallback();
 89             return null;
 90         }
 91         // 5.获取令牌桶中的令牌,如果能在有效期获取令牌到令的话,则直接进入到实际请求方法中。
 92         // 直接进入实际请求方法中
 93         return proceedingJoinPoint.proceed();
 94     }
 95 
 96     private void fallback() throws IOException {
 97         System.out.println("服务降级别抢了, 在抢也是一直等待的, 还是放弃吧!!!");
 98         // 在AOP编程中获取响应
 99         ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
100         HttpServletResponse response = attributes.getResponse();
101         response.setHeader("Content-type", "text/html;charset=UTF-8");
102         PrintWriter writer = response.getWriter();
103         try {
104             writer.println("别抢了, 在抢也是一直等待的, 还是放弃吧!!!");
105         } catch (Exception e) {
106 
107         } finally {
108             writer.close();
109 
110         }
111 
112     }
113 
114     private String getRequestURI() {
115         return getRequest().getRequestURI();
116     }
117 
118     private HttpServletRequest getRequest() {
119         ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
120         return attributes.getRequest();
121     }
122 
123     // 获取到AOP拦截的方法
124     private Method getSinatureMethod(ProceedingJoinPoint proceedingJoinPoint) {
125         MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
126         // 获取到AOP拦截的方法
127         Method method = signature.getMethod();
128         return method;
129     }
130 
131 }

猜你喜欢

转载自www.cnblogs.com/xjatj/p/10646383.html