Guava RateLimiter + AOP注解实现单机限流

 

依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>30.1.1-jre</version>
        </dependency>

 

自定义运行时注解:

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XcRateLimit {

    /**
     * @return
     */
    String value() default "";

    /**
     * 每秒向桶中放入令牌的数量   默认最大即不做限流
     *
     * @return
     */
    double perSecond() default Double.MAX_VALUE;

    /**
     * 获取令牌的等待时间  默认0
     *
     * @return
     */
    int timeOut() default 0;

    /**
     * 超时时间单位
     *
     * @return
     */
    TimeUnit timeOutUnit() default TimeUnit.MILLISECONDS;
}

 

aop切面进行环绕通知:

import com.google.common.util.concurrent.RateLimiter;
import com.xc.xcspringboot.common.annotation.XcRateLimit;
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.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;

import java.lang.reflect.Method;

@Aspect
@Component
public class XcRateLimitAspect {

    private final static Logger logger = LoggerFactory.getLogger(XcRateLimitAspect.class);

    private RateLimiter rateLimiter = RateLimiter.create(Double.MAX_VALUE);

    /**
     * 定义切点
     * 1、通过扫包切入
     * 2、带有指定注解切入
     */
//    @Pointcut("execution(public * com.xc.xcspringboot.*.*(..))")
    @Pointcut("@annotation(com.xc.xcspringboot.common.annotation.XcRateLimit)")
    public void checkPointcut() {
    }

    @ResponseBody
    @Around(value = "checkPointcut()")
    public Object aroundNotice(ProceedingJoinPoint pjp) throws Throwable {
        logger.info("拦截到了{}方法...", pjp.getSignature().getName());
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        //获取目标方法
        Method targetMethod = methodSignature.getMethod();
        if (targetMethod.isAnnotationPresent(XcRateLimit.class)) {
            //获取目标方法的@LxRateLimit注解
            XcRateLimit lxRateLimit = targetMethod.getAnnotation(XcRateLimit.class);
            rateLimiter.setRate(lxRateLimit.perSecond());
            if (!rateLimiter.tryAcquire(lxRateLimit.timeOut(), lxRateLimit.timeOutUnit()))
                return "同时调用次数过多,请稍后再试!";
        }
        return pjp.proceed();
    }
}

 

在controller中使用自定义注解:

@RestController
@RequestMapping("/testRateLimiter")
@Slf4j
public class TestRateLimiterController {

    @RequestMapping("/testAnnotation")
    @XcRateLimit(perSecond = 1.0, timeOut = 500)
    public String testAnnotation() {
        return "get success";
    }


}

 

参考: https://www.cnblogs.com/myseries/p/12634557.html

posted @ 2021-07-15 09:21  草木物语  阅读(456)  评论(0编辑  收藏  举报