快速搭建 SpringCloudStream Kafka

Spring Cloud Stream是一个构建消息驱动微服务的框架,简化了与消息中间件的交互。它支持发布-订阅模型、消费组和分区等特性,并提供自动配置支持RabbitMQ和Kafka等中间件。本文介绍其核心概念、配置及示例代码。

什么是 Spring cloud stream ?

官方定义 Spring Cloud Stream 是一个构建消息驱动微服务的框架。
应用程序通过 inputs 或者 outputs 来与 Spring Cloud Stream 中binder 交互,通过我们配置来 binding ,而 Spring Cloud Stream 的 binder 负责与消息中间件交互。所以,我们只需要搞清楚如何与 Spring Cloud Stream 交互就可以方便使用消息驱动的方式。

通过使用Spring Integration来连接消息代理中间件以实现消息事件驱动。Spring Cloud Stream 为一些供应商的消息中间件产品提供了个性化的自动化配置实现,引用了发布-订阅、消费组、分区的三个核心概念。支持异常自动重试机制,并且可输入到dlq队列中。目前仅支持RabbitMQ、Kafka。

Stream解决了开发人员无感知的使用消息中间件的问题,因为Stream对消息中间件的进一步封装,可以做到代码层面对中间件的无感知,甚至于 动态的切换中间件 (rabbitmq切换为kafka),使得微服务开发的高度解耦,服务可以关注更多自己的业务流程

官方结构图:
在这里插入图片描述

常用注解:

注解描述
@Input注解标识 输入 通道,通过该输入通道接收到的消息进入应用程序。
@Output注解标识 输出 通道,发布的消息将通过该通道离开应用程序。
@StreamListener监听队列,用于消费者的队列的 消息接收
@EnableBinding指信道channel和exchange绑定在一起

根据Spring Boot 版本 找到相对应的 Spring Cloud Stream Kafka 版本 文档

官网文档:https://spring.io/projects/spring-cloud-stream#overview

demo

引入maven文件

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-stream-binder-kafka</artifactId>
</dependency>
<!-- 或  -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>

定义一个Processor通道

public interface IProcessor {
    String INPUT = "input";
	String OUTPUT = "output";
    /**
     * 创建一个输入通道
     *
     * @return
     */
    @Input(IProcessor.INPUT)
    SubscribableChannel in();
    /**
     * 创建一个输出通道
     *
     * @return
     */
    @Output(IProcessor.OUTPUT)
    MessageChannel out();
}

实现消息输出通道

/**
 * 消息发送
 */
@Service
public class SendService {
    @Resource
    private IProcessor processor;

	/**
	 * 通过该方法发送一条记录
	 */
    public void raceCarSoreLikeOut(String msg){
		// 发送一条记录
      	processor.out()
        	.send(
					// 消息生成器转换
                	MessageBuilder.withPayload(msg)
							// 可以设置 发送请求头 这里设置了 kafka_messageKey
                        	.setHeader(
                                	KafkaHeaders.MESSAGE_KEY,
                                	msg.getBytes(StandardCharsets.UTF_8)
                        	).build()
        	);
    }
}

实现consume


/**
 * 消费者
 * 通过EnableBinding 绑定信道 可以输入多 @EnableBinding({a.class,b.class})
 */
@EnableBinding(IProcessor.class)
public class ConsumerService {
	/**
 	 * 实现方式 一
 	 */
	@StreamListener(IProcessor.INPUT)
	public void in(Message<String> payload) {
		// 业务实现
		// 获取消息体
		payload.getPayload();
		// 获取请求头
		payload.getHeaders();
	}
	
	/**
 	 * 实现方式 二 ......推荐使用 String 进行传输
 	 */
	@StreamListener(IProcessor.INPUT)
	public void in(@Payload String payload,@Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) byte[] keymessageKey) {
		// 业务实现
	}
}

application.yml 文件

# spring cloud stream kafka config
spring:
  cloud:
    stream:
      kafka:
        binder:
          # Kafka的消息中间件服务器 地址
          brokers: ${kafka.bootstrap-servers}
		  # 开启自动分区
          auto-add-partitions: true
  		  # 关闭自动创建 topic
          auto-create-topics: false
        streams:
          binder:
			# 配置 处理 Binder 中的异常
			#    logAndContinue,    记录 并 继续
			#    logAndFail,   默认  记录 并 失败
			#    sendToDlq;         成功 并 加入死信队列
            deserializationExceptionHandler: sendToDlq
        bindings:
	 	  # 这里就是在 IProcessor 定义的 INPUT
          input:
            consumer:
			  # 是否开启 dlq 队列
              enable-dlq: ${kafka.topic.A-topic.dlq}
			  # 默认开启 启动自平衡模式 可以轮询消费多台服务
              auto-rebalance-enabled: true
			  # 指定 dlq 队列名称 默认为 error.<destination>.<group>
              dlq-name: ${kafka.topic.A-topic.dlq-name}
			  # 是否开启自动提交 默认开启 
              auto-commit-offset: false
      bindings:
        output:
		  # 指定生产 topic 
          destination: ${kafka.topic.A-topic}
		  # 消息转换器 默认 application/json
          content-type: text/plain
          producer:
            partition-key-expression: payload
        input:
		  # 指定消费 topic 
          destination: ${kafka.topic.A-topic}
		  # 消息转换器 默认 application/json
          content-type: text/plain
          # 分组
          group: ${kafka.topic.A-topic.group}
		  # 消费的一些设置参数 如 开启分区、重试次数... 具体看官网提供的文档
          consumer:
            partitioned: true

<think>我们正在搭建Spring CloudKafka集成的微服务。首先需要明确,Spring Cloud本身并不直接提供与Kafka集成的模块,但我们可以通过Spring Cloud Stream或Spring Kafka来实现。Spring Cloud Stream是一个用于构建消息驱动微服务的框架,它支持多种消息中间件,包括Kafka。而Spring Kafka则是SpringKafka的直接封装。 下面将分别介绍两种方式,并给出示例代码。 方式一:使用Spring Cloud Stream集成Kafka 步骤: 1. 创建Spring Boot项目,添加依赖:Spring Cloud Stream和Kafka的binder。 2. 配置输入输出通道。 3. 编写消息生产者和消费者。 方式二:使用Spring Kafka集成 步骤: 1. 创建Spring Boot项目,添加Spring Kafka依赖。 2. 配置Kafka服务器地址和消费者组等。 3. 使用KafkaTemplate发送消息,使用@KafkaListener消费消息。 由于问题中提到了Spring Cloud,我们更倾向于使用Spring Cloud Stream,因为它提供了与消息中间件无关的统一编程模型,便于切换消息中间件。 下面以Spring Cloud Stream为例,详细说明: 步骤1:创建项目并添加依赖 使用Spring Initializr(https://start.spring.io/)创建一个Spring Boot项目,选择以下依赖: - Spring Cloud Stream - 对于Kafka绑定器,我们选择`spring-cloud-starter-stream-kafka` 或者,在pom.xml中添加: ```xml <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-kafka</artifactId> </dependency> </dependencies> ``` 步骤2:配置application.yml ```yaml spring: cloud: stream: bindings: output: # 生产者通道 destination: test-topic content-type: application/json input: # 消费者通道 destination: test-topic group: myGroup content-type: application/json kafka: binder: brokers: localhost:9092 # Kafka服务器地址 ``` 步骤3:定义通道接口 ```java import org.springframework.cloud.stream.annotation.Input; import org.springframework.cloud.stream.annotation.Output; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.SubscribableChannel; public interface KafkaChannels { String OUTPUT = "output"; String INPUT = "input"; @Output(OUTPUT) MessageChannel output(); @Input(INPUT) SubscribableChannel input(); } ``` 步骤4:编写消息生产者 在需要发送消息的地方注入MessageChannel,并发送消息。 ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.messaging.support.MessageBuilder; @EnableBinding(KafkaChannels.class) public class KafkaProducer { @Autowired private MessageChannel output; public void sendMessage(String message) { output.send(MessageBuilder.withPayload(message).build()); } } ``` 步骤5:编写消息消费者 ```java import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.annotation.StreamListener; @EnableBinding(KafkaChannels.class) public class KafkaConsumer { @StreamListener(KafkaChannels.INPUT) public void handleMessage(String message) { System.out.println("Received message: " + message); } } ``` 步骤6:在Spring Cloud微服务中使用 在Spring Cloud微服务中,你可以将上述生产者和消费者作为Bean注入,然后在需要的地方调用。 注意:以上示例使用的是Spring Cloud Stream的旧版注解(如@EnableBinding, @StreamListener),在Spring Cloud Stream 3.x之后,推荐使用函数式编程模型。下面给出函数式编程模型的示例: 使用函数式编程模型(推荐): 步骤1:依赖不变 步骤2:配置application.yml,同上,但可以简化通道定义(使用函数式接口) 步骤3:编写一个生产者Bean和一个消费者Bean 生产者: ```java import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; import java.util.function.Supplier; @Service public class KafkaProducer { @Bean public Supplier<String> output() { return () -> "Hello, Kafka!"; // 实际中可能需要动态消息,这里仅示例 } } ``` 消费者: ```java import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; import java.util.function.Consumer; @Service public class KafkaConsumer { @Bean public Consumer<String> input() { return message -> { System.out.println("Received: " + message); }; } } ``` 然后在配置文件中绑定函数: ```yaml spring: cloud: stream: function: definition: output; input # 定义函数名,这里output和input对应上面两个Bean的方法名 bindings: output-out-0: # 函数名output,输出通道(out),索引0(因为函数可能有多个输出,这里只有一个) destination: test-topic input-in-0: # 函数名input,输入通道(in),索引0 destination: test-topic group: myGroup kafka: binder: brokers: localhost:9092 ``` 注意:函数式编程模型中,函数名(如output, input)对应绑定通道,规则为:函数名+方向(in/out)+索引。默认情况下,输出通道是函数名+“-out-” + 索引,输入通道是函数名+“-in-” + 索引。 以上两种方式都可以实现Spring CloudKafka的集成。根据实际需求选择。 另外,关于Kafka配置,如序列化、反序列化、错误处理等,可以在配置文件中进一步设置。 最后,确保Kafka服务已经启动。 相关问题: 1. Spring Cloud Stream与Spring Kafka有什么区别? 2. 在Spring Cloud Stream中如何处理消息序列化? 3. 如何保证Kafka消息的可靠传递? 4. 在微服务架构中,如何利用Kafka实现事件驱动? 5. Spring Cloud Stream函数式编程模型有哪些优势?</think>### Spring CloudKafka集成微服务搭建指南 #### 一、核心组件与依赖 1. **Spring Cloud Stream** 提供统一的消息编程模型,支持Kafka作为消息中间件 2. **Spring Kafka** 直接操作Kafka的底层API 3. **依赖配置** (pom.xml): ```xml <!-- Spring Cloud Stream + Kafka Binder --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-kafka</artifactId> <version>3.2.4</version> </dependency> <!-- Spring Kafka (可选) --> <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency> ``` #### 二、配置步骤 1. **配置文件** (application.yml) ```yaml spring: cloud: stream: bindings: output: # 生产者通道 destination: orders-topic content-type: application/json input: # 消费者通道 destination: orders-topic group: payment-service content-type: application/json kafka: binder: brokers: localhost:9092 # Kafka集群地址 auto-create-topics: true ``` 2. **消息生产者** ```java @EnableBinding(Source.class) public class OrderProducer { @Autowired private Source source; public void sendOrder(Order order) { source.output().send(MessageBuilder .withPayload(order) .setHeader("orderType", "VIP") .build() ); } } ``` 3. **消息消费者** ```java @EnableBinding(Sink.class) public class PaymentConsumer { @StreamListener(Sink.INPUT) public void handle(Order order, @Header("orderType") String type) { System.out.println("Received order: " + order.getId()); // 处理支付逻辑 } } ``` 4. **实体类示例** ```java public class Order implements Serializable { private Long id; private BigDecimal amount; // getters/setters } ``` #### 三、高级配置 1. **消息分区** ```yaml bindings: output: producer: partition-key-expression: headers['orderId'] # 按订单ID分区 partition-count: 3 # 分区数量 ``` 2. **消息重试机制** ```yaml spring: cloud: stream: bindings: input: consumer: max-attempts: 3 # 最大重试次数 back-off-initial-interval: 1000 # 重试间隔(ms) ``` 3. **死信队列配置** ```yaml kafka: binder: dead-letter-topic-encoding: utf-8 dead-letter-topic-name: orders-topic.DLT ``` #### 四、部署验证 1. **启动Kafka** ```bash # 单节点快速启动 docker run -d --name kafka \ -p 9092:9092 \ -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 \ bitnami/kafka ``` 2. **测试消息流** - 发送测试消息:`POST /orders` ```json {"id": 1001, "amount": 99.99} ``` - 查看消费日志: ``` 2023-10-05 INFO: Received order: 1001 ``` #### 五、微服务集成方案 ```mermaid graph LR A[订单服务] -->|Kafka消息| B(订单主题) B --> C[支付服务] B --> D[库存服务] B --> E[日志服务] ``` #### 六、常见问题解决 1. **消息序列化错误** 确保所有服务使用相同的序列化格式: ```yaml spring: cloud: stream: default: contentType: application/json ``` 2. **消费者组冲突** 每个微服务使用独立消费者组: ```yaml spring: cloud: stream: bindings: input: group: ${spring.application.name} # 使用服务名作为组ID ``` 3. **性能优化** ```yaml spring: kafka: listener: concurrency: 3 # 并发消费者数 batch-listener: true # 启用批量消费 ``` > 最佳实践:生产环境建议使用Kubernetes部署Kafka集群,通过Spring Cloud Config统一管理配置[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值