记录一下每特教育所学的限流注解
1.定义注解
package com.example.test.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 王健宇
* @title: VisitLimit
* @description
* @date 2021/6/23 8:38
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface VisitLimit {
/**
* 几个令牌
* @return
*/
int token() default 1;
/**
* 访问路径名
* @return
*/
String name();
}
2.定义aop切面,并在切面中引用guava的RateLimiter实现限流
package com.example.test.aop;
import com.example.test.anno.VisitLimit;
import com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author 王健宇
* @title: VisitLimitAop
* @description
* @date 2021/6/23 8:47
*/
@Aspect
@Component
public class VisitLimitAop {
public static RateLimiter rateLimiter = RateLimiter.create(1.0);
private Map<String, RateLimiter> rateLimiters = new ConcurrentHashMap<>();
@Around(value = "@annotation(com.example.test.anno.VisitLimit)")
public Object round(ProceedingJoinPoint joinPoint) {
try {
// 1.获取注解参数值
// 1.1 获取方法
Signature sig = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) sig;
// 1.2 获取注解
VisitLimit visitLimit = methodSignature.getMethod().getDeclaredAnnotation(VisitLimit.class);
// 1.3获取注解的name和token值
String name = visitLimit.name();
int token = visitLimit.token();
// 2.装载进容器
RateLimiter rateLimiter = rateLimiters.get(name);
if (rateLimiter == null) {
rateLimiter = RateLimiter.create(token);
rateLimiters.put(name, rateLimiter);
}
boolean b = rateLimiter.tryAcquire();
if (!b) {
return "访问人数过多";
}
System.out.println("环绕前置通知");
Object proceed = joinPoint.proceed();
System.out.println("环绕后置通知");
return proceed;
} catch (Throwable throwable) {
throwable.printStackTrace();
return "报错";
}
}
}
3.测试
package com.example.test.ctrl;
import com.example.test.anno.VisitLimit;
import com.google.common.util.concurrent.RateLimiter;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 王健宇
* @title: DemoController
* @description
* @date 2021/6/22 21:53
*/
@RestController
public class DemoController {
@RequestMapping("/get")
@VisitLimit(name = "get")
public String get () {
return "get";
}
@RequestMapping("/add")
@VisitLimit(name = "add", token = 5)
public String add () {
return "add";
}
}
4.运行结果
快速点击刷新能模拟出来
由于add接口使用的是5个token,所以一般需要专业测试工具可以模拟