令牌桶的自定义注解核心API演示

@Aspect
@Component
public class RateLimiterAop {
    // 创建map,key是URL,value是令牌,同一个请求就覆盖上一个值
    private static ConcurrentHashMap<String, RateLimiter> rateLimiterMap = new ConcurrentHashMap<String, RateLimiter>();
  //切入点拦截com.lzh.demo包下的所有的public类和方法
    @Pointcut("execution(public * com.lzh.demo.*(..))")
    public void rlAop() {
    }
     //使用AOP环绕通知判断拦截所有springmvc的请求,判断请求方法上是否存在ExtRateLimiter 
    @Around("rlAop()")
    public Object doBefore(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
     //判断是否存在@ExtRateLimiter注解
        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对象,保证每个请求都是单例的,比如很多的同一个pay请求可以共用一个ratelimiter,
   //但是如果是order请求,那么就必须再创建一个ratelimiter,根据URL进行判断
private RateLimiter getRateLimiter(double value, long timeOut) { // 获取当前URI ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); String requestURI = request.getRequestURI(); RateLimiter rateLimiter = null; if (!rateLimiterMap.containsKey(requestURI)) { // 如果没有检测到URI,那么创建一个新的ratelimiter rateLimiter = RateLimiter.create(value); // 独立线程 rateLimiterMap.put(requestURI, rateLimiter); } else { // 能够在map中检测到URL就添加到map中,相同的请求在同一个ratemiliter中 rateLimiter = rateLimiterMap.get(requestURI); } return rateLimiter; } // 服务降级 private void serviceDowng() throws IOException {
     // 获取响应 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(); } } }
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtRateLimiter {
  // 以秒为单位的速率往桶中存令牌
double value();   // 规定的毫秒内如果没有得到令牌那么就走降级服务 long timeOut(); }
package com.lzh.demo

// 测试代码

@RequestMapping("/myOrder") @ExtRateLimiter(value = 10.0, timeOut = 500) public String myOrder() throws InterruptedException { System.out.println("myOrder"); return "SUCCESS"; }

 

posted @ 2018-08-29 16:51  奥克兰毛泽西  阅读(246)  评论(0编辑  收藏  举报