SpringBoot 接口防抖实现方案

举报
bug菌 发表于 2024/11/28 22:58:00 2024/11/28
【摘要】 🤔 前言:接口防抖,你了解了吗?程序员们,想必大家都有过这种经历:在开发过程中,频繁地收到重复请求,这不仅增加了服务器的负担,还可能导致一些意外的系统崩溃。尤其是当我们在做用户交互时,用户的一次操作可能会触发多次请求,比如输入框的实时搜索、按钮的多次点击等,这些请求如果不加以限制,服务器就会像受伤的战士一样,无法承受过多的压力。那么,如何避免这种重复请求的情况呢?防抖(Debouncin...

🤔 前言:接口防抖,你了解了吗?

程序员们,想必大家都有过这种经历:在开发过程中,频繁地收到重复请求,这不仅增加了服务器的负担,还可能导致一些意外的系统崩溃。尤其是当我们在做用户交互时,用户的一次操作可能会触发多次请求,比如输入框的实时搜索、按钮的多次点击等,这些请求如果不加以限制,服务器就会像受伤的战士一样,无法承受过多的压力。

那么,如何避免这种重复请求的情况呢?防抖(Debouncing)机制应运而生,它可以有效减少频繁触发接口的次数。今天就让我们一起探讨如何在 SpringBoot 中实现接口防抖功能,帮你提高系统性能,避免过多不必要的请求带来的困扰。准备好了吗?让我们一起动手,写点“防抖”的代码吧!🖋️

🎯 防抖机制的基本原理

防抖的核心思想其实很简单:在一段时间内多次触发的事件,只有最后一次触发事件在延时结束后才会被处理。就像你在“搜索框”里不停输入内容,如果没有防抖机制,每输入一个字符就会触发一次请求,这样就太浪费资源了。防抖的作用就是:只有当用户停止输入超过设定的时间,才会发送请求。这样,你可以避免重复的请求,减少服务器压力,同时提升用户体验。

举个例子:假设你在搜索框里输入“Java”,每个字母的输入都会触发一次请求。没有防抖的情况下,输入“J”就触发请求,输入“a”再触发请求,用户输入到“Java”时,可能已经触发了三四次请求。如果加上防抖,只会在用户输入完并且停顿一段时间后才会真正发送请求。

💡 SpringBoot 中实现接口防抖

在 SpringBoot 中,我们可以采用几种不同的方式来实现防抖机制。下面我将通过两种常见的方法来展示如何实现防抖:一种是通过 Redis 来存储请求的时间戳,另一种是通过线程池延时执行请求。让我们一起来看看如何实现!

1. 使用 Redis 存储请求时间戳

Redis 作为一个高性能的内存数据库,非常适合用来做防抖。我们可以通过 Redis 存储每个请求的时间戳,在同一时间窗口内,如果有重复请求到达,我们就不再处理,直接返回“请求被忽略”。等到时间窗口过去,才会处理真正需要的请求。

代码实现

首先,确保你已经在 SpringBoot 项目中集成了 Redis。你可以在 application.properties 文件中配置 Redis 的连接信息:

spring.redis.host=localhost
spring.redis.port=6379

接下来,我们在控制器中实现防抖逻辑:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class DebounceController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    // 防抖间隔时间,单位:秒
    private static final long DEBOUNCE_INTERVAL = 3;

    @GetMapping("/search")
    public String search(String query) {
        // 构建 Redis 键,基于查询参数
        String redisKey = "debounce:search:" + query;

        // 获取上次请求的时间戳
        String lastRequestTime = redisTemplate.opsForValue().get(redisKey);

        // 如果上次请求时间存在,并且距离当前时间不到防抖间隔,直接返回
        if (lastRequestTime != null && System.currentTimeMillis() - Long.parseLong(lastRequestTime) < DEBOUNCE_INTERVAL * 1000) {
            return "Request ignored to prevent debounce";
        }

        // 如果超出防抖间隔,更新 Redis 中的时间戳
        redisTemplate.opsForValue().set(redisKey, String.valueOf(System.currentTimeMillis()), DEBOUNCE_INTERVAL, TimeUnit.SECONDS);

        // 模拟请求的实际处理过程
        return "Search results for: " + query;
    }
}

在这个例子中,我们用 Redis 来存储每次请求的时间戳。如果用户在防抖时间窗口内重复请求,我们就跳过处理,避免重复触发接口。当请求时间超过设定的防抖间隔时,才会正常执行操作。

代码解析:

接着我将对上述代码逐句进行一个详细解读,希望能够帮助到同学们,能以最快的速度对其知识点掌握于心,这也是我写此文的初衷,授人以鱼不如授人以渔,只有将其原理摸透,日后应对场景使用,才能得心应手,如鱼得水。所以如果有基础的同学,可以略过如下代码解析,针对没基础的同学,还是需要加强对代码的逻辑与实现,方便日后的你能更深入理解它并常规使用不受限制。

这段代码展示了如何利用 Redis 来实现防抖机制,以避免频繁的请求对后端系统造成压力。在该示例中,防抖机制通过设置一个时间间隔,确保在该时间间隔内相同的请求只会被处理一次。下面是代码的详细解析:

  1. 依赖注入和 Redis 配置

    • @Autowired 注解将 StringRedisTemplate 注入到 DebounceController 中。StringRedisTemplate 是 Spring Data Redis 提供的操作 Redis 的模板,专门用于处理字符串类型的数据。
  2. 防抖间隔

    • DEBOUNCE_INTERVAL 常量设置为 3 秒,表示防抖的时间间隔。即,用户发出的相同请求在 3 秒内会被忽略。
  3. 防抖逻辑

    • @GetMapping("/search") 注解将 search() 方法与 /search 路由绑定。
    • String redisKey = "debounce:search:" + query;:构建 Redis 键,基于用户的查询 query,确保每个查询对应一个唯一的 Redis 键。
    • String lastRequestTime = redisTemplate.opsForValue().get(redisKey);:从 Redis 中获取上次请求的时间戳(即 redisKey 对应的值)。
  4. 请求防抖判断

    • 如果 Redis 中已经存储了上次请求的时间戳,并且当前请求与上次请求的时间间隔小于设定的防抖时间(3 秒),则返回 "Request ignored to prevent debounce",即忽略当前请求。
    • 如果当前请求与上次请求的时间间隔大于防抖间隔(3 秒),则说明超出了防抖时间窗口,允许处理请求。
  5. 更新时间戳

    • 当请求被允许处理时,通过 redisTemplate.opsForValue().set(redisKey, String.valueOf(System.currentTimeMillis()), DEBOUNCE_INTERVAL, TimeUnit.SECONDS); 将当前的时间戳写入 Redis,并设置过期时间为防抖间隔(3 秒)。这样,下次相同的请求会在 3 秒内被忽略。
  6. 请求处理

    • 模拟搜索处理并返回一个搜索结果信息:return "Search results for: " + query;

防抖机制的工作原理:

  • 防抖机制的关键在于,通过 Redis 存储上次请求的时间戳,确保同一查询在设定的时间窗口内不会频繁触发后端的处理逻辑。这在实际应用中非常有用,尤其是在搜索框、按钮点击等场景中,防止过多无效请求对系统造成负担。

扩展和改进:

  • 可以根据需要调整 DEBOUNCE_INTERVAL 的值,适应不同的场景。
  • 可以根据具体需求扩展功能,例如增加不同的查询类型对应不同的防抖机制,或者为每个用户/会话设定单独的防抖时间等。

总体来说,利用 Redis 来存储和检查上次请求的时间戳,是实现防抖机制的一种非常有效的方式,确保了系统的高效性和响应速度。

2. 使用线程池延时执行

另一种防抖方法是通过线程池来延迟执行请求,确保每个请求都被处理,但是防止短时间内的重复请求浪费资源。我们可以使用 ScheduledExecutorService 或者 Spring 提供的 @Scheduled 注解来实现延时操作。

代码实现

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
@EnableAsync
public class DebounceController {

    private static final long DEBOUNCE_DELAY = 3; // 防抖延迟时间,单位:秒

    private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

    @GetMapping("/search")
    public String search(String query) {
        executorService.schedule(() -> {
            // 实际的搜索请求逻辑
            System.out.println("Search executed for: " + query);
        }, DEBOUNCE_DELAY, TimeUnit.SECONDS);
        return "Search request received";
    }
}

在这个示例中,我们通过 ScheduledExecutorService 来延迟执行搜索请求。每次用户触发请求时,都会向线程池提交一个任务,并设置延迟时间。即便多次点击触发,只有当延迟时间结束后,才会真正执行一次搜索操作。

这种方式的优点是简洁易懂,并且可以很容易地调整延迟时间。不过,缺点是每个请求都需要通过线程池去执行,可能会增加线程池的管理复杂性。

代码解析:

接着我将对上述代码逐句进行一个详细解读,希望能够帮助到同学们,能以最快的速度对其知识点掌握于心,这也是我写此文的初衷,授人以鱼不如授人以渔,只有将其原理摸透,日后应对场景使用,才能得心应手,如鱼得水。所以如果有基础的同学,可以略过如下代码解析,针对没基础的同学,还是需要加强对代码的逻辑与实现,方便日后的你能更深入理解它并常规使用不受限制。

这段代码展示了如何利用 ScheduledExecutorService 实现防抖机制。具体的实现思路是,利用定时任务延迟执行搜索请求,确保在防抖延迟时间内的重复请求会被合并成一次执行。下面是对代码的详细解析:

  1. 依赖注入和配置

    • @EnableAsync 注解启用了 Spring 的异步方法执行支持,但在这段代码中并没有实际使用 @Async 注解,防抖逻辑是通过 ScheduledExecutorService 实现的。
    • ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); 创建了一个单线程的调度线程池,用于延迟执行搜索请求。
  2. 防抖延迟时间

    • DEBOUNCE_DELAY 常量设置为 3 秒,表示防抖的延迟时间。如果同一个查询在 3 秒内重复请求,只会执行一次搜索操作。
  3. 处理搜索请求

    • @GetMapping("/search") 注解绑定了一个 HTTP GET 请求,接收查询参数 query,并将请求传递到 search() 方法进行处理。
    • executorService.schedule() 方法用于调度一个任务,在指定的延迟时间后执行。这里的任务是一个 Runnable,其作用是执行实际的搜索逻辑。
    • schedule() 的参数包括:
      • 第一个参数:要执行的任务(此处是模拟的搜索操作,打印出搜索的内容)。
      • 第二个参数:延迟执行的时间(DEBOUNCE_DELAY,即 3 秒)。
      • 第三个参数:时间单位(TimeUnit.SECONDS)。
  4. 请求响应

    • 当用户发送一个搜索请求时,search() 方法会立即返回 "Search request received",并且将搜索操作延迟 3 秒执行。
    • 如果在 3 秒内有重复请求触发,它们会继续被调度到定时任务队列,但实际上每次搜索请求的处理会被合并成一次执行(即延迟后的搜索操作仅执行最后一次触发的请求)。

防抖机制的工作原理:

  • 防抖机制的核心是通过延迟执行搜索操作,如果短时间内收到相同请求,就会合并这些请求,而不是立即执行。具体来说,当接收到请求时,ScheduledExecutorService 会在 3 秒后执行搜索任务。如果在这 3 秒内有新的请求触发,之前的搜索任务会被替换或延迟,最终只会执行最新的请求。
  • 这种方法有助于减少对后端的压力,尤其是在用户输入框中频繁输入时(如搜索框)。只在最后一次输入之后才执行实际的搜索操作。

扩展和改进:

  • 多线程支持:如果需要处理多个并发请求,可以将 ScheduledExecutorService 替换为支持多个线程的线程池,或者为每个用户/会话维护一个独立的调度器。
  • 任务取消:如果请求在防抖延迟时间内取消(比如用户删除输入框内容),可以通过某种机制取消上一次调度的任务,避免无效的搜索请求执行。

这种基于定时调度的防抖方式可以有效减少频繁请求的资源消耗,尤其适用于需要控制用户输入频率的场景。

🔥 总结:如何选择合适的防抖方案?

从上述实现可以看到,不同的防抖方案有各自的优缺点。选择合适的防抖方式需要根据项目的实际情况来定。

  • Redis 防抖:适用于高并发、高频率请求的场景,能够有效减少重复请求对服务器的压力,并且支持分布式环境。
  • 线程池延时执行:适用于请求不需要立刻处理的场景,能通过线程池延时处理,避免请求的重复执行。

总之,防抖机制的引入能大大提高系统的性能,减少无效请求,尤其是在高并发的场景下,防抖能有效缓解服务器压力。希望你通过这篇文章,能够理解并在自己的项目中实现防抖功能!🎉

🧧福利赠与你🧧

  无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。

最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。

✨️ Who am I?

我是bug菌,CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云2023年度十佳博主,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;更多精彩福利点击这里;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。

-End-

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。