使用Guava提供的RateLimiter实现SpringBoot项目中基于注解的限流库.
Guava提供的RateLimiter可以限制物理或逻辑资源的被访问速率,咋一听有点像java并发包下的Samephore,但是又不相同,RateLimiter控制的是速率,Samephore控制的是并发量。
RateLimiter的原理类似于令牌桶,它主要由许可发出的速率来定义,如果没有额外的配置,许可证将按每秒许可证规定的固定速度分配,许可将被平滑地分发,若请求超过permitsPerSecond则RateLimiter按照每秒 1/permitsPerSecond
的速率释放许可。
<dependency>
<groupId>com.github.wjw465150</groupId>
<artifactId>rate-limiter-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
implementation group: 'com.github.wjw465150', name: 'rate-limiter-spring-boot-starter', version: '1.2.0'
直接在类需要限流的方法上加上注解@RateLimit
,进行限流
例如 :
package TestRateLimitStarter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.springframework.stereotype.Component;
import org.wjw.starter.limiter.RateLimit;
@Component
public class MyRateLimitTask {
@RateLimit(/* 每秒允许的许可数 */ permitsPerSecond = 2)
void doRunWork1(int i) {
System.out.println(currentTime() + ": doRunWork1 call execute.." + i);
}
@RateLimit(/* 每秒允许的许可数 */ permitsPerSecond = 1,
/* 此方法每次需要获得许可证的数量,默认是1个 */ permits = 2)
void doRunWork2(int i) {
System.out.println(currentTime() + ": doRunWork2 call execute.." + i);
}
private String currentTime() {
LocalDateTime dateTime = LocalDateTime.now();
return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"));
}
}
可以写一个SpringBoot的启动类来测试:
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package TestRateLimitStarter;
import javax.annotation.Resource;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TestApplication implements CommandLineRunner {
@Resource
private MyRateLimitTask limitTask;
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
for (int i = 1; i <= 10; i++) {
limitTask.doRunWork1(i);
}
for (int i = 1; i <= 10; i++) {
limitTask.doRunWork2(i);
}
}
}
输出如下:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.10.RELEASE)
2021-10-18 18:20:06.817 INFO 17128 --- [ main] TestRateLimitStarter.TestApplication : Starting TestApplication on WJW-T14 with PID 17128 (C:\WJW_E\WJW_DATA\OpenSource\SpringBoot-2\eclipse_workspace_rate-limiter\rate-limiter\rate-limiter-test\bin\main started by 86189 in C:\WJW_E\WJW_DATA\OpenSource\SpringBoot-2\eclipse_workspace_rate-limiter\rate-limiter\rate-limiter-test)
2021-10-18 18:20:06.819 INFO 17128 --- [ main] TestRateLimitStarter.TestApplication : No active profile set, falling back to default profiles: default
2021-10-18 18:20:07.435 INFO 17128 --- [ main] TestRateLimitStarter.TestApplication : Started TestApplication in 0.849 seconds (JVM running for 1.531)
2021-10-18 06:20:07: doRunWork1 call execute..1
2021-10-18 06:20:07: doRunWork1 call execute..2
2021-10-18 06:20:08: doRunWork1 call execute..3
2021-10-18 06:20:08: doRunWork1 call execute..4
2021-10-18 06:20:09: doRunWork1 call execute..5
2021-10-18 06:20:09: doRunWork1 call execute..6
2021-10-18 06:20:10: doRunWork1 call execute..7
2021-10-18 06:20:10: doRunWork1 call execute..8
2021-10-18 06:20:11: doRunWork1 call execute..9
2021-10-18 06:20:11: doRunWork1 call execute..10
2021-10-18 06:20:11: doRunWork2 call execute..1
2021-10-18 06:20:13: doRunWork2 call execute..2
2021-10-18 06:20:15: doRunWork2 call execute..3
2021-10-18 06:20:17: doRunWork2 call execute..4
2021-10-18 06:20:19: doRunWork2 call execute..5
2021-10-18 06:20:21: doRunWork2 call execute..6
2021-10-18 06:20:23: doRunWork2 call execute..7
2021-10-18 06:20:25: doRunWork2 call execute..8
2021-10-18 06:20:27: doRunWork2 call execute..9
2021-10-18 06:20:29: doRunWork2 call execute..10