这是一个 单进程 Spring Boot 应用:同一个 JVM 里既有 HTTP 接口(生产者),也有 @KafkaListener(消费者),中间通过 Kafka Broker(192.168.1.7:9092)上的 test_topic 传递消息。

1. HTTP 入口:KafkaTestController
@GetMapping("/send")
public String send(@RequestParam String text) {
kafkaMsgProducer.sendMsg(text);
return "消息发送成功:" + text;
}
逻辑:
- 客户端访问
GET http://localhost:8080/send?text=某内容 - Spring MVC 把
text绑定到方法参数 - 调用
kafkaMsgProducer.sendMsg(text)发 Kafka 消息 - 立刻返回
"消息发送成功:" + text,不等待消费完成
注意:这里 sendMsg 没有 await 发送结果,HTTP 响应只表示「已调用发送」,不保证 Broker 已持久化(实际 KafkaTemplate.send 默认异步,见下文)。
2. 生产端:KafkaMsgProducer + KafkaTemplate
public void sendMsg(String content) {
// 参数1:topic名称,参数2:消息内容
kafkaTemplate.send("test_topic", content);
}
kafkaTemplate.send("test_topic", content) 在 Spring Kafka 内部大致做了:
| 步骤 | 说明 |
|---|---|
|
构造记录 |
生成 |
|
序列化 |
用 |
|
选分区 |
未指定 key,按默认分区策略(通常轮询或 sticky)写入某个 partition |
|
发送 |
底层 |
|
确认 |
|
KafkaTemplate 和 KafkaProducer 由 Spring Boot 自动配置(spring-kafka + KafkaAutoConfiguration)根据 application.yml 创建,无需手写配置类。
3. Kafka 配置:application.yml
spring:
kafka:
bootstrap-servers: 192.168.1.7:9092
# 生产者配置
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
# 发送确认机制 1=leader写入成功即返回
acks: 1
# 消费者配置
consumer:
group-id: test-boot-group
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
auto-offset-reset: earliest
enable-auto-commit: true
与链路相关的点:
- bootstrap-servers:应用启动时连接
192.168.1.7:9092发现集群元数据 - acks: 1:Leader 写入即返回,不等待所有 ISR 同步(吞吐更好,极端情况下可能丢消息)
- group-id: test-boot-group:消费者组 ID,同组内分区只被一个实例消费
- auto-offset-reset: earliest:无已提交 offset 时从最早消息开始读
- enable-auto-commit: true:消费后由客户端定时自动提交 offset,业务代码里不用手动 commit
4. 应用启动时的消费者注册
@SpringBootApplication
public class KafkaDemoServiceApplication {
public static void main(String[] args) {
SpringApplication.run(KafkaDemoServiceApplication.class,args);
@SpringBootApplication 会扫描并注册:
KafkaMsgProducer(@Component)KafkaMsgConsumer(@Component)- 启用
@KafkaListener注解处理(@EnableKafka由自动配置引入)
启动后,Spring Kafka 会为 KafkaMsgConsumer.listen 创建 监听容器(ConcurrentMessageListenerContainer),在后台线程持续对 test_topic 执行 poll()。
5. 消费端:KafkaMsgConsumer
// 监听test_topic主题
@KafkaListener(topics = "test_topic")
public void listen(String msg) {
System.out.println("SpringBoot消费者收到消息:" + msg);
}
消费流程:
- 监听容器轮询
test_topic(消费者组test-boot-group) - Broker 返回新消息的字节
StringDeserializer反序列化为String,注入listen(String msg)- 执行
System.out.println(...)打印到控制台 - 方法正常返回后,由
enable-auto-commit: true在后台周期提交 offset
消费与 HTTP 请求 不在同一线程:/send 返回后,消费通常在几百毫秒内异步完成(取决于 Broker 和网络)。
6. 端到端时序(结合源码)
以 GET /send?text=hello 为例:
1. Tomcat 线程处理 HTTP
└─ KafkaTestController.send("hello")
2. KafkaMsgProducer.sendMsg("hello")
└─ kafkaTemplate.send("test_topic", "hello")
└─ StringSerializer → 字节
└─ KafkaProducer → 192.168.1.7:9092 / test_topic / partition N
3. Controller 返回 "消息发送成功:hello"(HTTP 结束)
4. Kafka Broker 持久化消息,维护 offset
5. 监听容器线程 poll 到新消息
└─ StringDeserializer → "hello"
└─ KafkaMsgConsumer.listen("hello")
└─ 控制台: SpringBoot消费者收到消息:hello
7. 几个容易忽略的细节
(1)生产与消费在同一应用
生产者、消费者都在本服务里,所以你会看到:调一次 /send,控制台很快出现消费日志。生产环境常见的是不同服务分别生产和消费。
(2)send 是异步的
当前代码没有 .get() 或回调,Controller 返回时消息可能还在缓冲区。若要「发送成功再返回」,需要类似:
kafkaTemplate.send("test_topic", content).get(); // 或 addCallback
(3)未指定 message key
send(topic, content) 没有 key,同一 topic 内消息会分散到各分区;若需要同一 key 顺序消费,应使用 send(topic, key, content)。
(4)无自定义错误处理
发送失败、消费异常都没有 try-catch 或 @RetryableTopic,会依赖 Spring Kafka 默认重试/日志行为。
(5)依赖关系
pom.xml 中 spring-kafka 提供 KafkaTemplate、@KafkaListener 及自动配置;spring-boot-starter-web 提供 REST 能力。
总结
| 层级 | 类/配置 | 职责 |
|---|---|---|
|
接口层 |
|
接收 HTTP,调用生产者 |
|
生产层 |
|
序列化并发送到 |
|
中间件 |
Kafka Broker |
存储、分发消息 |
|
消费层 |
|
后台 poll、反序列化、打印 |
|
配置 |
|
连接地址、序列化、acks、消费者组、offset |
整条链路就是:HTTP → Producer → Kafka Topic → Consumer 监听线程 → 控制台输出,由 Spring Boot + Spring Kafka 自动装配完成,业务代码只写了薄薄三层(Controller / Producer / Consumer)。

2109

被折叠的 条评论
为什么被折叠?



