注:本人所有的spring-cloud系列的文章均为黑马的《Spring Cloud微服务架构开发》的个人笔记。
基于Spring Cloud的消息驱动框架Stream
- 了解Spring Cloud Stream的基本概念
- 熟悉Spring Cloud Stream 与RabbitMQ结合使用
- 熟悉Stream的发布-订阅模式的概念
- 熟悉Stream的消费组与消息分区的使用
作用:使用Spring Cloud Stream整合消息中间件降低系统和中间件的耦合性;是spring cloud对于消息中间件的进一步封装;使用其可忽略消息中间件之间的差异,有效降低开发人员对消息中间件的使用复杂度。
;目前支持的消息中间件只有RabbitMQ和Kafka
Spring Cloud Stream应用模型:
1.入门案例
首先需要在本地安装RabbitMQ,此案例通过RabbitMQ中间件接收消息并打印在控制台
1.1 创建springboot项目stream-hello
添加依赖web 、test 以及stream-rabbit
<!--该依赖用于提供Spring Cloud Stream对RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
1.2 创建消息消费类rabbitmq.SinkReceiver
@EnableBinding(Sink.class) //开启绑定通道的注解 Sink是stream组件默认的输入通道接口
public class SinkReceiver {
private static Logger logger = LoggerFactory.getLogger(AinkReceiver.class);
@StreamListener(Sink.INPUT) //注解为监听器
public void receiver(String payload){
logger.info("Receiver:"+payload)
}
}
1.3 测试
先启动RibbitMQ 再启动stream-hello
浏览器访问:http://localhost:15672 登录RabbitMQ图形化界面
2.Stream的发布-订阅模式
消息提供者发送消息到RabbitMQ,消息消费者向RabbitMQ订阅消息,消息消费者在订阅的主题中收到它并触发自身的业务逻辑处理。
2.1 创建消息提供者stream-rabbitmq-provider
pom.xml文件
<!--该依赖用于提供Spring Cloud Stream对RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
application.yml
server:
port: 8898
spring:
application:
name: stream-rabbitmq-provider
rabbitmq: #安装到本地的mq,此节点会默认有以下值,可以不设置,通常mq单独部署在一台服务器
host: localhost
port: 5672
username: guest
password: guest
cloud:
stream:
bindings:
output:
destination: minestream #指定当前主题的名称 与消费者的一致
创建provider.StreamProvider类向mq发送消息
@EnableBinding(Source.class) //source是stream组件默认输出通道接口
@RestController
public class StreamProvider {
@Autowired
@Otput(Source.OUTPUT)
private MessageChannel channerl;
@GetMapping("/send")
public void send(){
channel.send(MessageBuilder.withPayload("hello world").build());
}
}
2.2 创建消息消费者stream-rabbitmq-consumer
pom.xml 同 消息提供者stream-rabbitmq-provider
application.yml
server:
port: 9898
spring:
application:
name: stream-rabbitmq-consumer
rabbitmq: #安装到本地的mq,此节点会默认有以下值,可以不设置,通常mq单独部署在一台服务器
host: localhost
port: 5672
username: guest
password: guest
cloud:
stream:
bindings:
output:
destination: minestream #指定当前主题的名称 与提供者的一致
创建consumer.StreamConsumer类订阅消息
@EnableBinding(Sink.class)
public class StreamConsumer {
@StreamListener(Sink.INPUT)
public void receiver(String payload){
System.out.println("接收到了mq中发送来的消息:"+ payload)
}
}
启动提供者和消费者
provider控制台:
consumer控制台:
3.Stream消费组
在实际开发中,微服务应用为了实现高可用和负载均衡,会部署多个实例。默认情况下,当消息提供者发出一条消息到绑定通道上,这条消息会被每个消费者实例接收和处理(出现了重复消费的问题)。Stream消费组即用来解决此问题
创建两个消息消费者 ,在其配置文件添加group如下代码:
spring:
cloud:
stream:
bindings:
input:
destination:minestream
group: stream # 两个消费者同
此时的mq图形化界面Queues只有一个队列
当访问 localhost:8898/send 的时候,只在其中一个消费者的控制台接收到消息,当再次访问 localhost:8898/send ,则在另一个消费者的控制台接收到消息,此消费者采用是是轮询法
4.消费分区
在特定情况下,mq接收到的消息需要同一个消费实例消费的时候,需要用到消费分区
在消息提供者是配置文件下添加如下参数:
spring:
cloud:
stream:
bindings:
output:
destination: minestream
provider:
#分区表达式,例如当表达式的值为1.那么在订阅者的instance-index中为1的接收方,将会执行该消息
partition-key-expression: 1
partition-count: 2 #参与消费分区的消费者数量
修改消息消费者1
spring:
cloud:
stream:
bindings:
input:
destination:minestream
group: stream
consumer:
partitioned: true # 是否开启分区
instance-count: 2 #分区数量 对齐bindings
instance-index: #当前实例的索引号 对齐bindings
修改消息消费者2
spring:
cloud:
stream:
bindings:
input:
destination:minestream
group: stream
consumer:
partitioned: true # 是否开启分区
instance-count: 2 #分区数量 对齐bindings
instance-index: 1 #当前实例的索引号 对齐bindings
######仅索引号不同
访问 localhost:8898/send 的时候 消费者2接收到消息