首先是自定义注解的实现
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {
int rate() default 100;
String mode() default RateLimitMode.SMOOTH_BURSTY;
}
自定义限流类型
public class RateLimitMode {
public static final String SMOOTH_BURSTY = "smooth-bursty";
public static final String SMOOTH_WARMING_UP = "smooth-warming-up";
}
切面的实现
@Aspect
@Component
@Order(100)
public class RateLimitAspect {
private static Logger LOGGER = LoggerFactory.getLogger(RateLimitAspect.class);
private static Map<String, Object> RateLimiterMap = new ConcurrentHashMap<String, Object>();
private volatile static int initServerNum = 0;
@Pointcut("@annotation(注解类全路径)")
public void rateLimitCutPoint() {
LOGGER.info("编入切入点");
}
@Before("rateLimitCutPoint()")
public void rateLimitBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getTarget().getClass().getSimpleName() + "." + joinPoint.getSignature().getName();
RateLimiter rateLimiter = (RateLimiter) RateLimiterMap.getOrDefault(methodName, RateLimiter.create(134));
double waitTime = rateLimiter.acquire();
LOGGER.info("acquire spend {} seconds", waitTime);
}
@Around("rateLimitCutPoint()")
public Object rateLimitAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
try {
Signature signature = proceedingJoinPoint.getSignature();
String methodName = proceedingJoinPoint.getTarget().getClass().getSimpleName() + "." + signature.getName();
RateLimit rateLimitAnnotation = ((MethodSignature) signature).getMethod().getDeclaredAnnotation(RateLimit.class);
int rate = rateLimitAnnotation.rate();
String mode = rateLimitAnnotation.mode();
putRate(methodName, rate, mode);
LOGGER.info("限流方法名{},执行速率{}", methodName, ((RateLimiter) RateLimiterMap.get(methodName)).getRate());
} catch (Exception e) {
LOGGER.error("限流切面出现异常,异常提示{}", e.getMessage());
}
return proceedingJoinPoint.proceed();
}
private void putRate(String methodName, int rate, String mode) {
if (Objects.isNull(RateLimiterMap.get(methodName))) {
if (mode.equals(RateLimitMode.SMOOTH_BURSTY)) {
RateLimiterMap.putIfAbsent(methodName, RateLimiter.create(rate));
} else {
RateLimiterMap.putIfAbsent(methodName, RateLimiter.create(rate, 1, TimeUnit.MINUTES));
}
}
}