概述
限流
限制在一定时间内允许访问接口的次数,防止过度请求对系统造成压力。
防抖
控制接口调用的频率,确保短时间内的多次调用合并为一次实际处理。
防重
防止重复请求对系统的影响,确保同一个请求只被处理一次。
实现注解和功能
创建限流注解
我们首先定义一个注解 @RateLimit,用于标识需要限流的方法。
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 RateLimit {
// 限流的时间窗口,单位是秒
int windowSeconds() default 60;
// 时间窗口内允许的最大请求次数
int maxRequests() default 100;
}
创建限流处理器
我们实现一个限流处理器,通过在方法调用时检查是否超出限制。
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class RateLimitProcessor {
private static final ConcurrentHashMap<String, RequestLimit> requestLimits = new ConcurrentHashMap<>();
public static boolean isAllowed(Method method) {
RateLimit rateLimit = method.getAnnotation(RateLimit.class);
// 如果没有注解,则不进行限流
if (rateLimit == null) {
return true;
}
String key = method.getDeclaringClass().getName() + "." + method.getName();
RequestLimit limit = requestLimits.computeIfAbsent(key, k -> new RequestLimit(rateLimit.windowSeconds(), rateLimit.maxRequests()));
return limit.isAllowed();
}
private static class RequestLimit {
private final int windowSeconds;
private final int maxRequests;
private final AtomicInteger requestCount;
private long windowStart;
RequestLimit(int windowSeconds, int maxRequests) {
this.windowSeconds = windowSeconds;
this.maxRequests = maxRequests;
this.requestCount = new AtomicInteger();
this.windowStart = System.currentTimeMillis();
}
synchronized boolean isAllowed() {
long currentTime = System.currentTimeMillis();
if (currentTime - windowStart > windowSeconds * 1000) {
windowStart = currentTime;
requestCount.set(0);
}
return requestCount.incrementAndGet() <= maxRequests;
}
}
}
创建防抖注解
定义一个注解 @Debounce 用于标识需要防抖处理的方法。
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 Debounce {
// 防抖的时间窗口,单位是毫秒
long windowMillis() default 300;
}
创建防抖处理器
实现一个防抖处理器,确保在短时间内的多次调用被合并。
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class DebounceProcessor {
private static final ConcurrentHashMap<String, DebounceTask> debounceTasks = new ConcurrentHashMap<>();
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
public static void schedule(Method method, Runnable task, long debounceMillis) {
String key = method.getDeclaringClass().getName() + "." + method.getName();
DebounceTask debounceTask = debounceTasks.computeIfAbsent(key, k -> new DebounceTask(task, debounceMillis));
debounceTask.schedule();
}
private static class DebounceTask {
private final Runnable task;
private final long debounceMillis;
private volatile long lastExecutionTime;
DebounceTask(Runnable task, long debounceMillis) {
this.task = task;
this.debounceMillis = debounceMillis;
this.lastExecutionTime = 0;
}
synchronized void schedule() {
long currentTime = System.currentTimeMillis();
long delay = debounceMillis - (currentTime - lastExecutionTime);
if (delay <= 0) {
lastExecutionTime = currentTime;
scheduler.submit(task);
} else {
lastExecutionTime = currentTime + delay;
scheduler.schedule(() -> {
if (currentTime >= lastExecutionTime) {
task.run();
}
}, delay, TimeUnit.MILLISECONDS);
}
}
}
}
创建防重注解
定义一个注解 @Deduplicate 用于标识需要防重处理的方法。
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 Deduplicate {
}
创建防重处理器
实现一个防重处理器,确保同一请求不会被重复处理。
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
public class DeduplicationProcessor {
private static final ConcurrentHashMap<String, Object> requestCache = new ConcurrentHashMap<>();
public static boolean isUnique(Method method, Object requestKey) {
Deduplicate deduplicate = method.getAnnotation(Deduplicate.class);
if (deduplicate == null) {
return true; // 如果没有注解,则不进行防重处理
}
return requestCache.putIfAbsent(requestKey.toString(), new Object()) == null;
}
}
集成处理器
我们需要在实际调用接口时,集成以上的限流、防抖和防重处理器。可以在方法调用前进行相应的检查或处理。
import java.lang.reflect.Method;
public class ApiService {
public void someMethod() {
Method method = getMethod("someMethod");
// 限流检查
if (!RateLimitProcessor.isAllowed(method)) {
throw new RuntimeException("Rate limit exceeded");
}
// 防抖处理
DebounceProcessor.schedule(method, this::performAction, 300);
// 防重处理
Object requestKey = generateRequestKey();
if (!DeduplicationProcessor.isUnique(method, requestKey)) {
return; // 如果请求不是唯一的,则不处理
}
performAction();
}
private void performAction() {
// 实际业务逻辑
}
private Method getMethod(String methodName) {
try {
return this.getClass().getMethod(methodName);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
private Object generateRequestKey() {
// 生成请求唯一标识的逻辑
return new Object();
}
}
总结
文章描述了如何通过自定义注解和基础 Java 代码实现接口限流、防抖和防重机制通过这种方式,我们可以在不依赖 SpringBoot 或其他框架的情况下,灵活地对接口进行控制,提高系统的稳定性和用户体验。