添加依赖
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
自定义限流拦截注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Limiting {
//默认每秒放入桶中的token(0.5也就是2秒1次)
double alias() default 0;
}
使用@PostConstruct和临时缓存充当从数据库读取数据
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RateLimit {
private Integer rateId;
/**
* 限流名称(类名)
*/
private String rateName;
/**
* 限流组名(组名,唯一)
*/
private String rateGroup;
/**
* 方法名称
*/
private String methodName;
/**
* 限流量
*/
private Double limit;
/**
* 状态(0正常 1暂停)
*/
private Integer state;
/**
* 备注信息
*/
private String remark;
}
@Component
public class RateLimitCache {
public static Map<Integer,RateLimit> map = new ConcurrentHashMap<>();
@PostConstruct
public void init(){
RateLimit rateLimit = new RateLimit(1,"rate","测试组名","rateLimit",3.0,0,"");
map.put(1,rateLimit);
}
}
aop拦截注解并设置限流
@Slf4j
@Component
@Aspect
public class RateLimitAspect {
private ConcurrentHashMap<String, RateLimiter> limitMap = new ConcurrentHashMap<>();
private RateLimiter rateLimiter;
@Pointcut("@annotation(com.bsj.demo.test.annotation.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 method = target.getClass().getMethod(msg.getName(), msg.getParameterTypes());
//获取注解中每秒加入令牌桶中的token
Limiting annotation = method.getAnnotation(Limiting.class);
//按照配置取限流次数
double limitNum = annotation.alias();
log.info("------------limitNum:" + limitNum);
Class<?> aClass = target.getClass();
// 获取Controller注解
Controller controller = aClass.getAnnotation(Controller.class);
String value = controller.value();
String name = method.getName();
//这里是处理数据与限流之间的关系,我就随便写写匹配
RateLimit rateLimit = RateLimitCache.map.get(1);
if (rateLimit.getRateName().equals(value) && rateLimit.getMethodName().equals(name) && !limitMap.containsKey("abc")){
log.info("获取值为:"+rateLimit.getLimit());
limitMap.put("abc", RateLimiter.create(rateLimit.getLimit()));
rateLimiter = limitMap.get("abc");
}
log.info("===================--------:"+rateLimiter.getRate());
boolean tryAcquire = rateLimiter.tryAcquire(10);
log.info("rateLimiter.tryAcquire(10):"+tryAcquire);
if (!tryAcquire) {
log.info("获取不到令牌拉---------------");
return "请求过于频繁";
}
return point.proceed();
}
}