封装RateLimiter 令牌桶算法

自定义注解封装RateLimiter.实例:

 

@RequestMapping("/myOrder")

@ExtRateLimiter(value = 10.0, timeOut = 500)

public String myOrder() throws InterruptedException {

           System.out.println("myOrder");

           return "SUCCESS";

}

 

自定义注解

@Target(value = ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface ExtRateLimiter {

      double value();

 

      long timeOut();

}

 

编写AOP

@Aspect

@Component

public class RateLimiterAop {

      // 存放接口是否已经存在

      private static ConcurrentHashMap<String, RateLimiter> rateLimiterMap = new ConcurrentHashMap<String, RateLimiter>();

 

      @Pointcut("execution(public * com.it.api.*.*(..))")

      public void rlAop() {

      }

 

      @Around("rlAop()")

      public Object doBefore(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

           MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();

           // 使用Java反射技术获取方法上是否有@ExtRateLimiter注解类

           ExtRateLimiter extRateLimiter = signature.getMethod().getDeclaredAnnotation(ExtRateLimiter.class);

           if (extRateLimiter == null) {

                 // 正常执行方法

                 Object proceed = proceedingJoinPoint.proceed();

                 return proceed;

           }

           // ############获取注解上的参数 配置固定速率 ###############

           // 获取配置的速率

           double value = extRateLimiter.value();

           // 获取等待令牌等待时间

           long timeOut = extRateLimiter.timeOut();

           RateLimiter rateLimiter = getRateLimiter(value, timeOut);

           // 判断令牌桶获取token 是否超时

           boolean tryAcquire = rateLimiter.tryAcquire(timeOut, TimeUnit.MILLISECONDS);

           if (!tryAcquire) {

                 serviceDowng();

                 return null;

           }

           // 获取到令牌,直接执行..

           Object proceed = proceedingJoinPoint.proceed();

           return proceed;

 

      }

 

      // 获取RateLimiter对象

      private RateLimiter getRateLimiter(double value, long timeOut) {

           // 获取当前URL

           ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

           HttpServletRequest request = attributes.getRequest();

           String requestURI = request.getRequestURI();

           RateLimiter rateLimiter = null;

           if (!rateLimiterMap.containsKey(requestURI)) {

                 // 开启令牌通限流

                 rateLimiter = RateLimiter.create(value); // 独立线程

                 rateLimiterMap.put(requestURI, rateLimiter);

           } else {

                 rateLimiter = rateLimiterMap.get(requestURI);

           }

           return rateLimiter;

      }

 

      // 服务降级

      private void serviceDowng() throws IOException {

           // 执行服务降级处理

           System.out.println("执行降级方法,亲,服务器忙!请稍后重试!");

           ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

           HttpServletResponse response = attributes.getResponse();

           response.setHeader("Content-type", "text/html;charset=UTF-8");

           PrintWriter writer = response.getWriter();

           try {

                 writer.println("执行降级方法,亲,服务器忙!请稍后重试!");

           } catch (Exception e) {

 

           } finally {

                 writer.close();

           }

 

      }

 

      public static void main(String[] args) {

           // 使用Java反射技术获取方法上是否有@ExtRateLimiter注解类

           ExtRateLimiter extRateLimiter = IndexController.class.getClass().getAnnotation(ExtRateLimiter.class);

           System.out.println(extRateLimiter);

      }

 

}

运行效果

@RequestMapping("/myOrder")

@ExtRateLimiter(value = 10.0, timeOut = 500)

public String myOrder() throws InterruptedException {

           System.out.println("myOrder");

           return "SUCCESS";

}

上一篇:redis做分布式服务限流


下一篇:ASP入门(二十一)- 如何自己获取 ADO 连接字符串