Skip to content

Commit ae4dd40

Browse files
committed
✨ 使用 Guava 限流实现
1 parent 2644612 commit ae4dd40

File tree

6 files changed

+174
-0
lines changed

6 files changed

+174
-0
lines changed

spring-boot-demo-ratelimit-guava/pom.xml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,32 @@
2828
<artifactId>spring-boot-starter-web</artifactId>
2929
</dependency>
3030

31+
<dependency>
32+
<groupId>org.springframework.boot</groupId>
33+
<artifactId>spring-boot-starter-aop</artifactId>
34+
</dependency>
35+
36+
<dependency>
37+
<groupId>cn.hutool</groupId>
38+
<artifactId>hutool-all</artifactId>
39+
</dependency>
40+
41+
<dependency>
42+
<groupId>com.google.guava</groupId>
43+
<artifactId>guava</artifactId>
44+
</dependency>
45+
3146
<dependency>
3247
<groupId>org.springframework.boot</groupId>
3348
<artifactId>spring-boot-starter-test</artifactId>
3449
<scope>test</scope>
3550
</dependency>
51+
52+
<dependency>
53+
<groupId>org.projectlombok</groupId>
54+
<artifactId>lombok</artifactId>
55+
<optional>true</optional>
56+
</dependency>
3657
</dependencies>
3758

3859
<build>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.xkcoding.ratelimit.guava.annotation;
2+
3+
import org.springframework.core.annotation.AliasFor;
4+
import org.springframework.core.annotation.AnnotationUtils;
5+
6+
import java.lang.annotation.*;
7+
import java.util.concurrent.TimeUnit;
8+
9+
/**
10+
* <p>
11+
* 限流注解,添加了 {@link AliasFor} 必须通过 {@link AnnotationUtils} 获取,才会生效
12+
*
13+
* @author yangkai.shen
14+
* @date Created in 2019/9/12 14:14
15+
* @see AnnotationUtils
16+
* </p>
17+
*/
18+
@Target(ElementType.METHOD)
19+
@Retention(RetentionPolicy.RUNTIME)
20+
@Documented
21+
public @interface RateLimiter {
22+
int NOT_LIMITED = 0;
23+
24+
/**
25+
* qps
26+
*/
27+
@AliasFor("qps") double value() default NOT_LIMITED;
28+
29+
/**
30+
* qps
31+
*/
32+
@AliasFor("value") double qps() default NOT_LIMITED;
33+
34+
/**
35+
* 超时时长
36+
*/
37+
int timeout() default 0;
38+
39+
/**
40+
* 超时时间单位
41+
*/
42+
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.xkcoding.ratelimit.guava.aspect;
2+
3+
import com.xkcoding.ratelimit.guava.annotation.RateLimiter;
4+
import lombok.extern.slf4j.Slf4j;
5+
import org.aspectj.lang.ProceedingJoinPoint;
6+
import org.aspectj.lang.annotation.Around;
7+
import org.aspectj.lang.annotation.Aspect;
8+
import org.aspectj.lang.annotation.Pointcut;
9+
import org.aspectj.lang.reflect.MethodSignature;
10+
import org.springframework.core.annotation.AnnotationUtils;
11+
import org.springframework.stereotype.Component;
12+
13+
import java.lang.reflect.Method;
14+
15+
/**
16+
* <p>
17+
* 限流切面
18+
* </p>
19+
*
20+
* @author yangkai.shen
21+
* @date Created in 2019/9/12 14:27
22+
*/
23+
@Slf4j
24+
@Aspect
25+
@Component
26+
public class RateLimiterAspect {
27+
private static final com.google.common.util.concurrent.RateLimiter RATE_LIMITER = com.google.common.util.concurrent.RateLimiter.create(Double.MAX_VALUE);
28+
29+
@Pointcut("@annotation(com.xkcoding.ratelimit.guava.annotation.RateLimiter)")
30+
public void rateLimit() {
31+
32+
}
33+
34+
@Around("rateLimit()")
35+
public Object pointcut(ProceedingJoinPoint point) throws Throwable {
36+
MethodSignature signature = (MethodSignature) point.getSignature();
37+
Method method = signature.getMethod();
38+
// 通过 AnnotationUtils.findAnnotation 获取 RateLimiter 注解
39+
RateLimiter rateLimiter = AnnotationUtils.findAnnotation(method, RateLimiter.class);
40+
if (rateLimiter != null && rateLimiter.qps() > RateLimiter.NOT_LIMITED) {
41+
double qps = rateLimiter.qps();
42+
log.debug("【{}】的QPS设置为: {}", method.getName(), qps);
43+
// 重新设置 QPS
44+
RATE_LIMITER.setRate(qps);
45+
// 尝试获取令牌
46+
if (!RATE_LIMITER.tryAcquire(rateLimiter.timeout(), rateLimiter.timeUnit())) {
47+
throw new RuntimeException("手速太快了,慢点儿吧~");
48+
}
49+
}
50+
return point.proceed();
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.xkcoding.ratelimit.guava.controller;
2+
3+
import cn.hutool.core.lang.Dict;
4+
import com.xkcoding.ratelimit.guava.annotation.RateLimiter;
5+
import lombok.extern.slf4j.Slf4j;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.RestController;
8+
9+
/**
10+
* <p>
11+
* 测试
12+
* </p>
13+
*
14+
* @author yangkai.shen
15+
* @date Created in 2019/9/12 14:22
16+
*/
17+
@Slf4j
18+
@RestController
19+
public class TestController {
20+
21+
@RateLimiter(value = 1.0, timeout = 300)
22+
@GetMapping("/test1")
23+
public Dict test1() {
24+
log.info("【test1】被执行了。。。。。");
25+
return Dict.create().set("msg", "hello,world!").set("description", "别想一直看到我,不信你快速刷新看看~");
26+
}
27+
28+
@GetMapping("/test2")
29+
public Dict test2() {
30+
log.info("【test2】被执行了。。。。。");
31+
return Dict.create().set("msg", "hello,world!").set("description", "我一直都在,卟离卟弃");
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.xkcoding.ratelimit.guava.handler;
2+
3+
import cn.hutool.core.lang.Dict;
4+
import org.springframework.web.bind.annotation.ExceptionHandler;
5+
import org.springframework.web.bind.annotation.RestControllerAdvice;
6+
7+
/**
8+
* <p>
9+
* 全局异常拦截
10+
* </p>
11+
*
12+
* @author yangkai.shen
13+
* @date Created in 2019/9/12 15:00
14+
*/
15+
@RestControllerAdvice
16+
public class GlobalExceptionHandler {
17+
18+
@ExceptionHandler(RuntimeException.class)
19+
public Dict handler(RuntimeException ex) {
20+
return Dict.create().set("msg", ex.getMessage());
21+
}
22+
}

spring-boot-demo-ratelimit-guava/src/main/resources/application.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@ server:
22
port: 8080
33
servlet:
44
context-path: /demo
5+
logging:
6+
level:
7+
com.xkcoding: debug

0 commit comments

Comments
 (0)