1. 程式人生 > 其它 >Guava RateLimiter + AOP註解實現單機限流

Guava RateLimiter + AOP註解實現單機限流

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