java限流-基于guava实现
1、引入guava依赖
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>23.0</version> </dependency>
2、自定义限流注解
自定义一个限流用的注解,后面在需要限流的方法或接口上面只需添加该注解即可;
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(value = ElementType.METHOD) @Retention(value = RetentionPolicy.RUNTIME) public @interface RateConfigAnno { String limitType(); double limitCount() default 5d; }
3、限流AOP类
通过AOP前置通知的方式拦截添加了上述自定义限流注解的方法,解析注解中的属性值,并以该属性值作为guava提供的限流参数,该类为整个实现的核心所在。
import com.alibaba.fastjson2.JSONObject; import com.google.common.util.concurrent.RateLimiter; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.Method; import java.util.Objects; @Aspect @Component public class GuavaLimitAop { private static Logger logger = LoggerFactory.getLogger(GuavaLimitAop.class); @Before("execution(@RateConfigAnno * *(..))") public void limit(JoinPoint joinPoint) { //1、获取当前的调用方法 Method currentMethod = getCurrentMethod(joinPoint); if (Objects.isNull(currentMethod)) { return; } //2、从方法注解定义上获取限流的类型 String limitType = currentMethod.getAnnotation(RateConfigAnno.class).limitType(); double limitCount = currentMethod.getAnnotation(RateConfigAnno.class).limitCount(); //使用guava的令牌桶算法获取一个令牌,获取不到先等待 RateLimiter rateLimiter = RateLimitHelper.getRateLimiter(limitType, limitCount); boolean b = rateLimiter.tryAcquire(); if (b) { System.out.println("获取到令牌"); }else { HttpServletResponse resp = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); JSONObject jsonObject=new JSONObject(); jsonObject.put("success",false); jsonObject.put("msg","限流中"); try { output(resp, jsonObject.toJSONString()); }catch (Exception e){ logger.error("error,e:{}",e); } } } private Method getCurrentMethod(JoinPoint joinPoint) { Method[] methods = joinPoint.getTarget().getClass().getMethods(); Method target = null; for (Method method : methods) { if (method.getName().equals(joinPoint.getSignature().getName())) { target = method; break; } } return target; } public void output(HttpServletResponse response, String msg) throws IOException { response.setContentType("application/json;charset=UTF-8"); ServletOutputStream outputStream = null; try { outputStream = response.getOutputStream(); outputStream.write(msg.getBytes("UTF-8")); } catch (IOException e) { e.printStackTrace(); } finally { outputStream.flush(); outputStream.close(); } } }
4、其中限流的核心API即为RateLimiter这个对象,涉及到的RateLimitHelper类如下
import com.google.common.util.concurrent.RateLimiter; import java.util.HashMap; import java.util.Map; public class RateLimitHelper { private RateLimitHelper(){} private static Map<String,RateLimiter> rateMap = new HashMap<>(); public static RateLimiter getRateLimiter(String limitType,double limitCount ){ RateLimiter rateLimiter = rateMap.get(limitType); if(rateLimiter == null){ rateLimiter = RateLimiter.create(limitCount); rateMap.put(limitType,rateLimiter); } return rateLimiter; } }
5、测试接口
@RestController public class TestController { @GetMapping("/save") @RateConfigAnno(limitType = "saveOrder",limitCount = 1) //每秒只能请求一次 public String save(){ return "success"; } }
吾乃代码搬运工,侵联删