什么是 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),使得微服务开发的高度解耦,服务可以关注更多自己的业务流程

官方结构图:

springcloud和kafka消息驱动 springcloud stream kafka_spring

常用注解:

注解

描述

@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