問題產生,當調用一個接口很頻繁的時候,比如每秒調用一個接口100次。業務提現在搶購等。這時我們的服務器處理不過來就會拒絕服務,宕機等等。。。顯然這不是我們需要的。
因此產生了限流這個。限流是什么呢,就是我只是接收那么多,多的就是等待,排隊,或者拒絕,然你等待,不進入服務。。。
直接上代碼:
@Inherited @Documented @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RateLimit { /** * 默認每秒支持100個 * @return */ int limintNum() default 100; }
/** * 限流 切面枚舉實現 * * @author mingge * */ @Component @Scope @Aspect @Slf4j public class RateLimitAspect { /** * //用來存放不同接口的RateLimiter(key為接口名稱,value為RateLimiter) */ private ConcurrentHashMap<String, RateLimiter> map = new ConcurrentHashMap<>(); private static final String POINT = "execution (* com.mingge..*.controller..*.*(..))"; private static ObjectMapper objectMapper = new ObjectMapper(); private RateLimiter rateLimiter; @Autowired private HttpServletResponse response; @Pointcut(POINT) public void serviceLimit() { } @Around("serviceLimit()") public Object around(ProceedingJoinPoint joinPoint) throws NoSuchMethodException { Object obj = null; //獲取攔截的方法名 Signature sig = joinPoint.getSignature(); //獲取攔截的方法名 MethodSignature msig = (MethodSignature) sig; //返回被織入增加處理目標對象 Object target = joinPoint.getTarget(); //為了獲取注解信息 Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes()); //獲取注解信息 RateLimit annotation = currentMethod.getAnnotation(RateLimit.class); //獲取注解每秒加入桶中的token int limitNum = annotation.limintNum(); // 注解所在方法名區分不同的限流策略 String functionName = msig.getName(); //獲取rateLimiter if(map.containsKey(functionName)){ rateLimiter = map.get(functionName); }else { map.put(functionName, RateLimiter.create(limitNum)); rateLimiter = map.get(functionName); } try { if (rateLimiter.tryAcquire()) { //執行方法 obj = joinPoint.proceed(); } else { BaseVO vo=new BaseVO(); vo.setCode(100001); vo.setMessage("系統繁忙,請稍后再試!"); //拒絕了請求(服務降級) String result = objectMapper.writeValueAsString(vo); log.info("拒絕了請求:" + result); outErrorResult(result); } } catch (Throwable throwable) { throwable.printStackTrace(); } return obj; } //將結果返回 public void outErrorResult(String result) { response.setContentType("application/json;charset=UTF-8"); try (ServletOutputStream outputStream = response.getOutputStream()) { outputStream.write(result.getBytes("utf-8")); } catch (IOException e) { e.printStackTrace(); } } static { objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); } }
使用方法就是在你控制器上面加上你注解即可:
@RateLimit(limintNum = 10)
這樣就起到了限流作用...這對於每秒請求頻繁,並發量大的接口有好處。。。毋庸置疑佬。。。