springboot 接口防抖技术实现思路

发布于:2025-03-27 ⋅ 阅读:(35) ⋅ 点赞:(0)

在Spring Boot应用中,接口防抖(Debounce)是一种常见的需求,特别是在处理高频触发的请求时,比如用户频繁点击按钮、自动补全搜索框等场景。防抖的目的是在一定时间内只执行一次操作,忽略其他重复的请求。

以下是几种实现接口防抖的方法:

1. 使用缓存

通过缓存机制来实现防抖。可以在第一次请求时缓存结果,并在指定时间内忽略后续的请求。

import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Service;

@Service
public class DebounceService {

    @Cacheable(value = "debounceCache", key = "#key")
    public String processRequest(String key) {
        // 模拟耗时操作
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Processed: " + key;
    }

    @CachePut(value = "debounceCache", key = "#key")
    public String updateCache(String key) {
        return null; // 不返回任何值,仅更新缓存时间
    }
}

在Controller中调用:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DebounceController {

    @Autowired
    private DebounceService debounceService;

    @GetMapping("/debounce")
    public String debounce(@RequestParam String key) {
        // 先更新缓存,确保缓存时间是最新的
        debounceService.updateCache(key);
        // 处理请求
        return debounceService.processRequest(key);
    }
}

配置缓存过期时间:

yaml

spring:
  cache:
    type: caffeine
    caffeine:
      spec: maximumSize=100,expireAfterWrite=5s

2. 使用限流

虽然限流和防抖不完全相同,但可以通过限流来间接实现防抖的效果。

import com.google.common.util.concurrent.RateLimiter;
import org.springframework.stereotype.Service;

@Service
public class RateLimiterService {

    private final RateLimiter rateLimiter = RateLimiter.create(1.0); // 每秒最多处理1个请求

    public String processRequest(String key) {
        if (rateLimiter.tryAcquire()) {
            // 模拟耗时操作
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Processed: " + key;
        } else {
            return "Request throttled";
        }
    }
}

在Controller中调用:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RateLimiterController {

    @Autowired
    private RateLimiterService rateLimiterService;

    @GetMapping("/rateLimiter")
    public String rateLimiter(@RequestParam String key) {
        return rateLimiterService.processRequest(key);
    }
}

3. 使用定时器

通过定时任务来实现防抖,确保在一定时间内只执行一次操作。

import org.springframework.stereotype.Service;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Service
public class DebounceExecutorService {

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private final ConcurrentHashMap<String, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();

    public void processRequest(String key, Runnable task) {
        ScheduledFuture<?> scheduledTask = scheduledTasks.get(key);
        if (scheduledTask != null) {
            scheduledTask.cancel(false); // 取消之前的任务
        }

        scheduledTask = scheduler.schedule(task, 5, TimeUnit.SECONDS); // 5秒后执行
        scheduledTasks.put(key, scheduledTask);
    }

    public void shutdown() {
        scheduler.shutdown();
    }
}

在Controller中调用:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DebounceExecutorController {

    @Autowired
    private DebounceExecutorService debounceExecutorService;

    @GetMapping("/debounceExecutor")
    public String debounceExecutor(@RequestParam String key) {
        debounceExecutorService.processRequest(key, () -> {
            // 模拟耗时操作
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Processed: " + key);
        });
        return "Request received, processing will start in 5 seconds if no new request arrives.";
    }
}

4. 使用分布式缓存防抖

在分布式环境中,可以使用Redis来实现防抖。通过设置带有过期时间的键来确保在一定时间内只处理一次请求。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class RedisDebounceService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    public String processRequest(String key) {
        Boolean isNew = redisTemplate.opsForValue().setIfAbsent(key, "processing", 5, TimeUnit.SECONDS);
        if (isNew != null && isNew) {
            // 模拟耗时操作
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            redisTemplate.delete(key); // 处理完成后删除键
            return "Processed: " + key;
        } else {
            return "Request throttled";
        }
    }
}

在Controller中调用:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RedisDebounceController {

    @Autowired
    private RedisDebounceService redisDebounceService;

    @GetMapping("/redisDebounce")
    public String redisDebounce(@RequestParam String key) {
        return redisDebounceService.processRequest(key);
    }
}

总结

  • 缓存防抖:适用于单机环境,简单易实现。
  • 限流:适用于需要控制请求速率的场景。
  • 定时任务防抖:适用于单机环境,可以精确控制执行时间。
  • Redis防抖:适用于分布式环境,确保多个实例之间的防抖一致性。