首先新建一个maven的springboot项目,pom文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.limit</groupId>
<artifactId>current-limiting</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>current-limiting</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
然后新建项目所需要的包路径
主启动类:CurrentLimitingApplication
package com.limit.currentlimiting;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CurrentLimitingApplication {
public static void main(String[] args) {
SpringApplication.run(CurrentLimitingApplication.class, args);
}
}
先定义一个注解类:Limit
package com.limit.currentlimiting.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Limit {
// 首先定义注解只是在方法上生效,其次定义注解是在运行时生效
/**
* name 限流的名称
*
* @return
*/
String name() default "";
/**
* token 限流的次数,每秒能够访问的次数
* @return
*/
double token() default 1.0D;
}
然后再定义一个AOP的类:LimitAop
package com.limit.currentlimiting.aop;
import com.google.common.util.concurrent.RateLimiter;
import com.limit.currentlimiting.annotation.Limit;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
@Aspect
@Component
public class LimitAop {
// 定义为一个组件注入Spring框架
// guava提供的限流方法
private ConcurrentHashMap<String, RateLimiter> rateLimiterConcurrentHashMap = new ConcurrentHashMap<>();
@Around(value = "@annotation(com.limit.currentlimiting.annotation.Limit)")
public Object around(ProceedingJoinPoint joinPoint) {
// 获取拦截的方法名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Limit limit = signature.getMethod().getDeclaredAnnotation(Limit.class);
double token = limit.token();
String name = limit.name();
RateLimiter rateLimiter = rateLimiterConcurrentHashMap.get(name);
if (rateLimiter == null) {
rateLimiter = RateLimiter.create(token);
rateLimiterConcurrentHashMap.put(name, rateLimiter);
}
boolean result = rateLimiter.tryAcquire((int) token);
if (!result) {
return "当前访问人数过多,请稍后重试~";
}
try {
return joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return "环绕通知";
}
}
最后再声明一个controller类:LimitController
package com.limit.currentlimiting.controller;
import com.google.common.util.concurrent.RateLimiter;
import com.limit.currentlimiting.annotation.Limit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LimitController {
@GetMapping("/get")
@Limit(name = "get", token = 1.0D)
public String get() {
return "get message";
}
}
运行结果:
如果F5按的慢,就是这样的:
如果F5按的快,就是这样的(因为我设置了1秒钟只允许最多一个请求访问):