package com.example.demo.controller; import com.example.demo.comment.RateLimit; import com.example.demo.comment.RateLimitAspectJ; import com.google.common.util.concurrent.RateLimiter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.StopWatch; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.PostConstruct; import java.lang.reflect.Method; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @RestController @RequestMapping("/limit") @Slf4j public class LimitController implements InitializingBean { //限流 private final RateLimiter rl = RateLimiter.create(2.0); /** * 使用goolge的guava实现接口限流处理 * * @return * @throws InterruptedException */ @PostMapping("/guava") public String rateLimit() throws InterruptedException { // StopWatch sw = new StopWatch(); sw.start(); boolean acquire = rl.tryAcquire(1000, TimeUnit.MILLISECONDS); log.info("guava实现接口限流rl{}",rl); // boolean acquire = rl.tryAcquire(); if (!acquire) { sw.stop(); log.info("没有拿到令牌,接口限流,time{}", sw.getTotalTimeMillis()); return "接口限流"; } //模拟接口执行 Thread.sleep(80L); sw.stop(); log.info("拿到令牌,接口完成time{}", sw.getTotalTimeMillis()); return "rateLimit"; } @PostMapping("/aspect2") @RateLimit(timeUnit = TimeUnit.MILLISECONDS, timeout = 2000, qps = 100.0) public String rateLimit2() throws InterruptedException { // log.info("guava实现接口限流"); StopWatch sw = new StopWatch(); sw.start(); //模拟接口执行 Thread.sleep(80L); sw.stop(); log.info("拿到令牌,接口完成time{}", sw.getTotalTimeMillis()); return "rateLimit"; } @PostMapping("/aspect") @RateLimit(timeUnit = TimeUnit.MILLISECONDS, timeout = 500, qps = 5) public String aspectLimit() { log.info("注解+切面 限流"); return "aspect"; } @Override public void afterPropertiesSet() throws Exception { log.info("这个类this={} ", this); Method aspectLimit = this.getClass().getMethod("rateLimit2"); RateLimit rateLimit = aspectLimit.getDeclaredAnnotation(RateLimit.class); log.info("rateLimit====" + rateLimit); final RateLimiter rateLmt = RateLimiter.create(rateLimit.qps(), rateLimit.timeout(), rateLimit.timeUnit()); RateLimitAspectJ.uriAndRateLimit.put("/limit/aspect2", rateLmt); log.info("初始化rateLmt={}", rateLmt); ConcurrentHashMap uriAndRateLimit =RateLimitAspectJ.uriAndRateLimit; uriAndRateLimit.forEachEntry(2,(m)->log.info(m.toString())); } @PostConstruct public void init() throws NoSuchMethodException { log.info("这个类this={} ", this); Method aspectLimit = this.getClass().getMethod("aspectLimit"); RateLimit rateLimit = aspectLimit.getDeclaredAnnotation(RateLimit.class); log.info("rateLimit====" + rateLimit); final RateLimiter rateLmt = RateLimiter.create(rateLimit.qps(), rateLimit.timeout(), rateLimit.timeUnit()); RateLimitAspectJ.uriAndRateLimit.put("/limit/aspect", rateLmt); log.info("初始化rateLmt={}", rateLmt); } // public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { // LimitController limitController = new LimitController(); // Class extends LimitController> aClass = limitController.getClass(); // Method aspectLimit = aClass.getMethod("aspectLimit"); // RateLimit rateLimit = aspectLimit.getDeclaredAnnotation(RateLimit.class); // log.info(rateLimit.toString()); // log.info("rateLimit====" + rateLimit); // final RateLimiter rateLmt = RateLimiter.create(rateLimit.qps(), rateLimit.timeout(), rateLimit.timeUnit()); // RateLimitAspectJ.uriAndRateLimit.put("/limit/aspect", rateLmt); // log.info("初始化rateLmt={}", rateLmt); // } }
//定义注解
package com.example.demo.comment; import java.lang.annotation.*; import java.util.concurrent.TimeUnit; /** * 限流注解:令牌桶方式 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RateLimit { //默认超时为秒 TimeUnit timeUnit() default TimeUnit.SECONDS; //等待超时 long timeout() default 10L;; //速率 x r/s 每秒支持多少个请求 double qps() default 100.0; }
//切面
package com.example.demo.comment; import com.google.common.util.concurrent.RateLimiter; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.concurrent.ConcurrentHashMap; @Order(2)//执行顺序,值越低优先级越高int的-多少开始 @Configuration @Aspect @Slf4j public class RateLimitAspectJ { public static final ConcurrentHashMap uriAndRateLimit = new ConcurrentHashMap(); @Pointcut("@annotation(com.example.demo.comment.RateLimit)") public void RLPointCut(){} @Around("RLPointCut()") public String handleLimit(ProceedingJoinPoint joinPoint){ log.info("joinPoint"+joinPoint); ServletRequestAttributes reatt = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); HttpServletRequest request = reatt.getRequest(); // String header = reatt.getRequest().getHeader("limitHead"); // if(null == header || !header.equals("tod")) // return "请求头加上tod"; String uri = request.getRequestURI(); RateLimiter rateLimit = (RateLimiter)uriAndRateLimit.get(uri); boolean acquire1 = rateLimit.tryAcquire(); log.info("acquire1={},limiter={},当前线程{}",acquire1,rateLimit,Thread.currentThread().getName()); if (!acquire1) { return "接口限流了"; } Object proceed = null; try { proceed = joinPoint.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } log.info("限流切面结果"+proceed); return "limit success" +proceed; } }