依赖
//guava依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
//AOP依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.17</version>
</dependency>
定义限流注解
package com.example.huibaozi.ratelimter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author jigua
* @version 1.0
* @className Limiting
* @description
* @create 2022/4/11 14:54
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Limiting {
//默认限流数量
double limitNum() default 20;
//限流方法名
String name() default "";
}
定义切面
package com.example.huibaozi.ratelimter;
import com.alibaba.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.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
/**
* @author jigua
* @version 1.0
* @className RateLimitAspect
* @description
* @create 2022/4/11 14:55
*/
@Aspect
@Component
@Slf4j
public class RateLimitAspect {
private ConcurrentHashMap<String, RateLimiter> RATE_LIMITER = new ConcurrentHashMap<>();
private RateLimiter rateLimiter;
@Pointcut("@annotation(com.example.huibaozi.ratelimter.Limiting)")
public void serviceLimit() {
}
@Around("serviceLimit()")
public Object around(ProceedingJoinPoint point) throws Throwable {
//获取拦截的方法名
Signature sig = point.getSignature();
//获取拦截的方法名
MethodSignature msg = (MethodSignature) sig;
//返回被织入增加处理目标对象
Object target = point.getTarget();
//为了获取注解信息
Method currentMethod = target.getClass().getMethod(msg.getName(), msg.getParameterTypes());
//获取注解信息
Limiting annotation = currentMethod.getAnnotation(Limiting.class);
//获取注解每秒加入桶中的token
double limitNum = annotation.limitNum();
// 注解所在方法名区分不同的限流策略
String functionName = msg.getName();
if (RATE_LIMITER.containsKey(functionName)) {
rateLimiter = RATE_LIMITER.get(functionName);
System.out.println("存在");
} else {
RATE_LIMITER.put(functionName, RateLimiter.create(limitNum));
rateLimiter = RATE_LIMITER.get(functionName);
System.out.println("put");
}
if (rateLimiter.tryAcquire()) {
log.info("处理完成");
return point.proceed();
} else {
throw new Exception("限流啦");
}
}
}
测试方法
- @Limiting(limitNum = 1,name = “testLimiter”)
- 配置限流个数和方法名
@RestController
public class UserController {
@GetMapping("/user/testLimiter")
@ResponseBody
@Limiting(limitNum = 1,name = "testLimiter")
public String testLimiter() throws Exception {
return "访问到啦";
}
}
测试
因为设置了限流次数为1,快速刷新网页(疯狂连击postman也行),就会抛出限流异常