了解RateLimiter
https://blog.csdn.net/qq_38366063/article/details/89070822
基于这个去实现的自定义限流注解.首先需要了解rateLimiter的简单使用.
导包只要spring,和guava包即可
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0.1-jre</version>
</dependency>
自定义注解,写切面
注解MyLimit
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;
/**
* @ClassName MyLimit
* @Description MyLimit
* @Author stack
* @Version 1.0
* @since 2019/7/15 16:47
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLimit {
/**
* 每秒向桶中放入令牌的数量
* 默认最大即不做限流,使用简单的RateLimit,每一秒中放入多少令牌
* @return
*/
int permitsPerSecond() default Integer.MAX_VALUE;
/**
* 获取令牌的等待时间 默认0
* @return
*/
int timeOut() default 0;
/**
* 超时时间单位
* @return
*/
TimeUnit unit() default TimeUnit.SECONDS;
}
限流切面:
import com.google.common.util.concurrent.RateLimiter;
import com.mr.common.ResultCode;
import com.mr.exception.MyprojectException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @ClassName MyLimit
* @Description MyLimit
* @Author stack
* @Version 1.0
* @since 2019/7/15 16:47
*/
@Aspect
@Component
@Slf4j
public class MyLimitAspect {
private static Map<String, RateLimiter> url = new ConcurrentHashMap<>();
@Pointcut("@annotation(com.mr.web.annotation.MyLimit)")
public void logPointCut() {
}
@Before("logPointCut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
MyLimit methodAnnotation = method.getAnnotation(MyLimit.class);
double v = methodAnnotation.permitsPerSecond();
if (v == Integer.MAX_VALUE) {
return;
}
if (methodAnnotation != null) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String requestURL = request.getRequestURL().toString();
//根据url判断是否限流。
if (url.containsKey(requestURL)) {
RateLimiter rateLimiter = url.get(requestURL);
if (!rateLimiter.tryAcquire(methodAnnotation.timeOut(), methodAnnotation.unit())) {
//限流
throw new MyprojectException(ResultCode.SYSTEM_ERROR.getError());
}
} else {
RateLimiter r = RateLimiter.create(v);
url.put(requestURL, r);
}
}
}
}
测试
随便写个测试的controller
当请求速度很快