@Aspect
@Component
public class LimitInterceptor {
@Autowired
private RedissonClient redissonClient;
@Value("${stnet.api.limit}")
private boolean limit;
/***配置织入点***/
@Pointcut("@annotation(com.st.microservice.plugin.sso.annotation.Limit)")
public void logPointCut() {
}
@Before(value = "logPointCut()")
public void interceptor(JoinPoint pjp) {
//限流开关
if(limit ==false)
{
return;
}
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
Limit limit = method.getAnnotation(Limit.class);
if(limit.limitType() == LimitType.IP) {
String key = "limit:" + IpUtils.getIpAddr();
redissonRateLimiter(limit, key);
}
if(limit.limitType() == LimitType.METHOD) {
String key = "limit:" + method.getClass().getSimpleName()+method.getName();
redissonRateLimiter(limit, key);
}
if(limit.limitType() == LimitType.IP_METHOD) {
String key = "limit:" + IpUtils.getIpAddr()+method.getClass().getSimpleName()+method.getName();
redissonRateLimiter(limit, key);
}
//开放接口
if(limit.limitType() == LimitType.USER_ID) {
if(ContextUtils.getUser()!= null) {
String key = "limit:" + ContextUtils.getUser().getUserId();
redissonRateLimiter(limit, key);
}
}
}
/**
* 获取Redisson的RRateLimiter
*
* @return
*/
private void redissonRateLimiter(Limit limit, String key) {
RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
if (!rateLimiter.isExists()) {
//创建一个RRateLimiter限流器,限流次数,注意count的值不能小于1,必须大于等于1
rateLimiter.trySetRate(RateType.OVERALL, limit.count(),limit.period(), RateIntervalUnit.SECONDS);
}
// 获取限流的配置信息
RateLimiterConfig rateLimiterConfig = rateLimiter.getConfig();
// 上次配置的限流时间毫秒值
Long rateInterval = rateLimiterConfig.getRateInterval();
// 上次配置的限流次数
Long rate = rateLimiterConfig.getRate();
// 将timeOut转换成毫秒之后再跟rateInterval进行比较
if (TimeUnit.MILLISECONDS.convert(limit.period(), TimeUnit.SECONDS) != rateInterval || limit.count() != rate) {
// 如果rateLimiterConfig的配置跟我们注解上面的值不一致,说明服务器重启过,程序员又修改了限流的配置
rateLimiter.delete();
// 以程序员重启后的限流配置为准,重新设置
rateLimiter.setRate(RateType.OVERALL, limit.count(), limit.period(), RateIntervalUnit.SECONDS);
}
//超时等待
if (limit.actor() == 1) {
rateLimiter.acquire();
}
//快速响应
if (limit.actor() == 2) {
//获取一个令牌,如果超过5秒没获取就超时处理
if(rateLimiter.tryAcquire(1,limit.timeout(),TimeUnit.SECONDS))
{
return;
}
throw new ServiceException("请求频繁,请稍后再试!", 400);
}
}
}
public enum LimitType {
/**
* 请求者IP -- 通常是某个IP 不过会有人进行虚拟IP进行访问
*/
IP,
/**
* 方法级别限流
* key = ClassName+MethodName
*/
METHOD,
/**
* 特定参数
* key = PARAM+MethodName
*/
USER_ID,
/**
* 用户级别限流
* key = USER_ID
*/
IP_METHOD
/**
* 用户级别限流
* key = ClassName+MethodName+Ip
*/
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Limit {
/***给定的时间范围 单位(秒)*/
int period() default 5;
/***一定时间内最多访问次数*/
int count() default 2;
/*** 限流的类型 */
LimitType limitType() default LimitType.IP_METHOD;
/*** 限流的类型 1 超时等待 2 快速返回*/
int actor() default 1;
/***一超时时间秒,当actor=2是生效*/
int timeout() default 3;
}