消息队列解耦及基本使用

消息队列的解耦,就是上下游服务相互依赖,但上游服务不关心下游服务结果,同时需要降低整体响应时间,且下游即便出现问题也不需要上游来解决的场景。

解耦演示场景

一个模块A接受前端请求,收到请求之后需要调用另一个模块B,以完成后续事项。一开始需要B做完之后,才回包给前端,这是第一种流程,这种流程很明显会很依赖模块B的运作情况。

但是如果业务允许,我们还可以有第二种流程:模块A不用等模块B把事情做完,只用将信息传递到一个中转站,B从中转站感知到这件事,再自己去做就可以了,这个中转站,就是消息队列,可以起到解耦的作用。

1. CountService.java(模拟耗时业务)

java 复制代码
package org.example.kafkademo1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class CountService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void doHeavyWork() {
        // 模拟耗时操作
        for (int i = 0; i < 1000000; i++) {
            if (i % 100000 == 0) {
                jdbcTemplate.update("UPDATE t_count SET count_value = count_value + 1 WHERE id = 1");
            }
        }
    }
}

2. DecouplingController.java(对比接口)

java 复制代码
package org.example.kafkademo1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/demo")
public class DecouplingController {

    @Autowired
    private CountService countService;
    
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    // 解耦前:同步调用,用户需要等待
    @GetMapping("/sync")
    public String sync() {
        long start = System.currentTimeMillis();
        countService.doHeavyWork();
        return "同步任务耗时:" + (System.currentTimeMillis() - start) + "ms";
    }

    // 解耦后:异步调用,秒回用户
    @GetMapping("/async")
    public String async() {
        long start = System.currentTimeMillis();
        // 丢给 Kafka 后直接返回
        kafkaTemplate.send("decoupling-topic", "start-task");
        return "解耦成功!用户感知耗时:" + (System.currentTimeMillis() - start) + "ms";
    }
}

3. KafkaConsumer.java(后台执行者)

java 复制代码
package org.example.kafkademo1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

@Component
public class KafkaConsumer {
    @Autowired
    private CountService countService;

    @KafkaListener(topics = "decoupling-topic", groupId = "my-group")
    public void handle(String message) {
        System.out.println(">>> Kafka 收到指令,后台开始干活...");
        countService.doHeavyWork();
        System.out.println(">>> 后台活干完了!");
    }
}

对比各自返回结果可得:

最后来抽象一下,解耦其实本质就是A不再关心B的事情,以及不再受B本身变动的影响

但是,MQ用来解耦和用来异步,这两者该如何区分?

  • 目的不一样,看业务的目的是什么
  • 比如一个服务觉得他不想关心后面服务的返回,这就是解耦
  • 如果一个服务,想关心结果,但是一次调用实在太久了,就是异步,回头还要轮询或者通过回调去得到结果。

Kafka的基本使用

通过上述应用场景总结,我们大概已经知道Kafka的基本用法,现在来整体做一个总结:

1.引入Maven依赖

pom.xml 中加入 spring-kafka。它会自动把底层的 Kafka 客户端驱动也带进来。

XML 复制代码
<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>

2. YAML/Properties 配置

这是最基础的连接配置,让你的 Java 程序能找到 Docker 里的 Kafka。

XML 复制代码
# 核心:Kafka 服务器地址
spring.kafka.bootstrap-servers=localhost:9092
# 消费者必须指定的组 ID
spring.kafka.consumer.group-id=my-group

简单来说,Group-ID 就是消费者的"团队名" :它让 Kafka 记住这个团队读到了哪一页 (Offset)以保证重启不丢进度,并让同组的多个成员分工协作 (负载均衡)处理同一个 Topic,从而实现海量数据的高效并行消费。既然你在配置里写了 my-group,Spring 就默认你所有的消费者方法都属于这个组。

3.代码

在 Java 代码里,只需要记住两个核心角色:发消息的 Template收消息的 Listener

生产者:KafkaTemplate (发件人)

它是 Spring 提供的一个工具类,你只需要 @Autowired 进来,然后调用**send**方法。

  • 特点 :异步执行。消息丢进缓冲区就立即返回,这就是你看到 0ms 的原因。
java 复制代码
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;

public void sendMessage(String msg) {
    // 参数:Topic名, 消息内容
    kafkaTemplate.send("my-topic", msg); 
}
消费者:@KafkaListener (收件人)

这是一个"被动触发"的注解。你不需要写死循环去读取消息,只要 Kafka 里有了新消息,Spring 会自动调用这个方法。

  • 特点:运行在独立的线程池里,不会阻塞主线程。
java 复制代码
@KafkaListener(topics = "my-topic")
public void listen(String message) {
    // 收到消息后的逻辑处理(比如你写的耗时计数)
    System.out.println("收到消息:" + message);
}
相关推荐
Devin~Y2 小时前
大厂 Java 面试实战:从电商微服务到 AI 智能客服(含 Spring 全家桶、Redis、Kafka、RAG/Agent 解析)
java·spring boot·redis·elasticsearch·spring cloud·docker·kafka
富士康质检员张全蛋2 小时前
Kafka JMS
分布式·kafka
fire-flyer3 小时前
ClickHouse系列(六):Kafka 到 ClickHouse 的生产级写入架构
clickhouse·架构·kafka
喜闻乐见天16 小时前
Kafka双机KRaft集群部署
kafka
Matrix7020 小时前
Kafka 单节点测试环境部署实战
大数据·kafka
Elastic 中国社区官方博客1 天前
将 Logstash 管道从 Azure Event Hubs 迁移到 Kafka 输入插件
大数据·数据库·elasticsearch·microsoft·搜索引擎·kafka·azure
indexsunny1 天前
互联网大厂Java面试实录:Spring Boot到微服务的深入探讨
java·spring boot·微服务·面试·eureka·kafka·jwt
海兰1 天前
Logstash 从 Azure Event Hubs 插件迁移至 Kafka 插件完整实战指南
kafka·linq·azure
zz0723201 天前
Apache Kafka 开源的分布式事件流平台
分布式·kafka·apache
却话巴山夜雨时i1 天前
互联网大厂Java面试实录:从Spring Boot到Kafka的场景应用深度解析
spring boot·kafka·prometheus·微服务架构·java面试·技术解析·互联网大厂