这样客户端在使用时:
RedisLimit redisLimit = new RedisLimit.Builder<>(jedisCluster) .limit(limit) .build();
更加的简单直接,并且避免了将创建过程分成了多个子步骤。
这在有多个构造参数,但又不是必选字段时很有作用。
因此顺便将分布式锁的构建器方式也一并更新了:
更多内容可以参考 Effective Java
API
从上文可以看出,使用过程就是调用 limit
方法。
//限流 boolean limit = redisLimit.limit(); if (!limit){ //具体限流逻辑 }
为了减少侵入性,也为了简化客户端提供了两种注解方式。
@ControllerLimit
该注解可以作用于 @RequestMapping
修饰的接口中,并会在限流后提供限流响应。
实现如下:
@Component public class WebIntercept extends WebMvcConfigurerAdapter { private static Logger logger = LoggerFactory.getLogger(WebIntercept.class); @Autowired private RedisLimit redisLimit; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new CustomInterceptor()) .addPathPatterns("/**"); } private class CustomInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (redisLimit == null) { throw new NullPointerException("redisLimit is null"); } if (handler instanceof HandlerMethod) { HandlerMethod method = (HandlerMethod) handler; ControllerLimit annotation = method.getMethodAnnotation(ControllerLimit.class); if (annotation == null) { //skip return true; } boolean limit = redisLimit.limit(); if (!limit) { logger.warn("request has bean limit"); response.sendError(500, "request limit"); return false; } } return true; } } }
其实就是实现了 SpringMVC 中的拦截器,并在拦截过程中判断是否有使用注解,从而调用限流逻辑。
前提是应用需要扫描到该类,让 Spring 进行管理。
@ComponentScan(value = "com.crossoverjie.distributed.intercept")
@CommonLimit
当然也可以在普通方法中使用。实现原理则是 Spring AOP (SpringMVC 的拦截器本质也是 AOP)。
@Aspect @Component @EnableAspectJAutoProxy(proxyTargetClass = true) public class CommonAspect { private static Logger logger = LoggerFactory.getLogger(CommonAspect.class); @Autowired private RedisLimit redisLimit ; @Pointcut("@annotation(com.crossoverjie.distributed.annotation.CommonLimit)") private void check(){} @Before("check()") public void before(JoinPoint joinPoint) throws Exception { if (redisLimit == null) { throw new NullPointerException("redisLimit is null"); } boolean limit = redisLimit.limit(); if (!limit) { logger.warn("request has bean limit"); throw new RuntimeException("request has bean limit") ; } } }
很简单,也是在拦截过程中调用限流。
当然使用时也得扫描到该包:
@ComponentScan(value = "com.crossoverjie.distributed.intercept")
总结
限流在一个高并发大流量的系统中是保护应用的一个利器,成熟的方案也很多,希望对刚了解这一块的朋友提供一些思路。
以上所有的源码: