当前位置: 首页 > news >正文

消息驱动Stream---基于SpringCloud

概要:实际开发中,服务与服务之间的通信经常会使用到消息中间件,而以往使用的一些消息中间件,比如RabbitMQ,该中间件和系统的耦合性非常高,如果我们要将RabbitMQ替换为Kafka,那么系统将会有较大的变动。此时,我们可以使用Spring Cloud Stream整合消息中间件降低系统和中间件的耦合性。

Spring Cloud Stream简介

什么是Spring Cloud Stream

概述Spring Cloud Stream是一个构建消息驱动微服务的框架

作用它是Spring Cloud对于消息中间件的进一步封装,通过使用Spring Cloud Stream,可忽略消息中间件之间的差异,有效降低开发人员对消息中间件的使用复杂度。 目前Spring Cloud Stream支持的消息中间件仅有RabbitMQKafka

Spring Cloud Stream 与消息中间件的交互

使用Stream构建的应用程序与消息中间件之间是通过绑定器Binder相关联的

Binder

特点Binder对于应用程序而言起到了隔离作用,它使得不同消息中间件的实现细节对Stream应用程序来说是透明的

用途对于每一个Stream的应用程序来说,Binder无需知晓消息中间件的通信细节,而是通过向应用程序暴露统一的通道(Channel)来进行通信。Binder是作为输入通道(inputs输出通道(outputs消息中间件之间的桥梁进行消息通信。

构建Stream工程

快速构建Stream工程

1.创建stream-hello项目

加入依赖:

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-stream-rabbit</artifactId><version>2.1.3.RELEASE</version></dependency></dependencies>

创建rabittmq包,并在rabittmq包中创建SinkReceiver类,用于接收RabbitMQ发送的消息 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;@EnableBinding(Sink.class)  //开启绑定通道的注解  Sink是Stream组件默认的输入通道接口
public class SinkReceiver {//声明日志private static Logger logger = LoggerFactory.getLogger(SinkReceiver.class);@StreamListener(Sink.INPUT)      //此注解声明此方法为监听方法private void receiver(String payload){logger.info("Receiver:"+payload);}
}
2.编写消息消费者类

@EnableBinding注解用来指定一个或多个定义了@Input@Output注解的接口,以此实现对消息通道(Channel)的绑定。

@StreamListener注解主要是修饰方法,用于将被修饰的方法注册为消息中间件上数据流的事件监听器,注解中的属性值对应了监听的消息通道名

3.项目测试

输入Rabbit MQ的可视化网址,账号密码默认为:guest

        第一个Spring Cloud Stream案例就完成了,但是我们会发现,此案例中并没有在配置文件 application.yml中进行任何属性设置,原因在于Spring Cloud Stream会为消息中间件RabbitMQ提供默认的自动化配置。当然我们也可以在Spring Boot支持的全局配置文件application.propertiesapplication.yml中修改相关配置。

Stream的发布-订阅模式

Stream的分布-订阅

特点:Spring Cloud Stream中的消息通信方式遵循的是发布-订阅模式,当一条消息被投递到消息中间件之后,它会通过共享主题的方式进行广播,消息消费者在订阅的主题中收到它并触发自身的业务逻辑处理。这里所提到的主题是Spring Cloud Stream中的一个抽象概念,用来代表发布共享消息给消费者的地方

Stream框架应用结构图

提供者发送消息到RabbitMQ等消息中间件,消费者通过订阅的方式从消息中间件获取消息。

搭建工程实现Stream的发布-订阅 

1.启动rabbitmq
2.创建提供者

依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><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-providerrabbitmq:host: localhostport: 5672username: guestpassword: guestcloud:stream:bindings:output:destination: minestream

 创建StreamProvider

 


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@EnableBinding(Source.class)
@RestController
public class StreamProvider {@Autowired@Output(Source.OUTPUT)private MessageChannel channel;@GetMapping("/send")public void send(){channel.send(MessageBuilder.withPayload("hello world").build());}
}
3.创建消费者

依赖和上面提供者一样(复制即可)

application.yml:

server:port: 9898
spring:application:name: stream-rabbitmq-consumerrabbitmq:host: localhostport: 5672username: guestpassword: guestcloud:stream:bindings:input:destination: minestream

创建StreamConsumer 

 

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;@EnableBinding(Sink.class)
public class StreamConsumer {@StreamListener(Sink.INPUT)public void receiver(String payload){System.out.println("接收到了mq中发送过来的消息"+payload);}
}
 4.测试运行

访问http://localhost:8898/send 地址发送消息,在消费者项目stream-rabbitmq-consumer的控制台可以看到打印日志“接收到MQ消息:Hello World!”,说明消息已成功被接收。

Stream的消费组和消息分区

Stream消费组的实现

Spring Cloud Stream应用程序开发中,如果在同一主题上的应用需要启动多个实例时,为防止对消息的重复处理,我们可以通过spring.cloud.stream.bindings.input. group属性为应用指定一个组名,这样一个应用的多个实例在接收到消息时,只会有一个实例真正收到消息并进行处理。

添加消费组

现在因为消费者是个集群,需要再复制多一个消费者,更改端口,并且两个消费者的配置文件加上group: stream

测试运行

依次启动stream-rabbitmq-provider,stream-rabbitmq-consumer,stream-rabbitmq-consumer2,在RabbitMQ控制台的 Queues可以看到两个队列合并为一个:minestream.stream

在浏览器访问http://localhost:8898/send

 

但再次访问http://localhost:8898/send时消费者2收到消息,而消费者1没有收到消息

说明:消息是以轮询的方式进行接收的

Stream的消息分区 

什么是Stream的消息分区?

        在消费组中我们可以保证消息不会被重复消费,但是在同组下有多个实例的时候,我们无法确定每次处理消息的是不是被同一消费者消费,这就要使用到Stream的消息分区,消息分区的作用就是为了确保具有共同特征标识的数据由同一个消费者实例进行处理。

1.改造提供者

修改提供者stream-rabbitmq-provider项目的application.yml配置文件

2.改造消费者

修改消费者stream-rabbitmq-consumer项目的application.yml配置文件

修改消费者stream-rabbitmq-consumer2项目的application.yml配置文件

 

3.启动测试

多次访问http://localhost:8898/send,发现在9899端口的控制台打印了多次日志信息“接收到MQ消息:Hello World!”,而9898端口的控制台没有,说明只有指定的分区可以接收到消息,这就是消费分区的作用。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【数据结构篇】~复杂度
  • 219页PDF || 大模型技术引领行业变革:2024大模型典型示范应用案例集(附案例集下载)
  • 鸿蒙开发入门day05-ArkTs语言(接口与关键字)
  • Matplotlib入门与进阶:数据可视化的强大工具
  • 灵办AI免费ChatGPT4人工智能浏览器插件快速便捷(多功能)
  • 【学习笔记】Matlab和python双语言的学习(最小生成树——Kruskal算法、Prim算法)
  • springBoot+ druid配置多数据源
  • qt工程中调用sdl的流程
  • centos8以上系统安装docker环境
  • CNN代码实战
  • OpenCV图像滤波(11)中值滤波medianBlur函数的使用
  • Lora 全文翻译
  • 搭建高可用OpenStack(Queen版)集群(九)之部署nova计算节点
  • Java基础——注解
  • ThreadLocal如何解决父子线程间通信问题?(上下文传递)
  • hexo+github搭建个人博客
  • ➹使用webpack配置多页面应用(MPA)
  • 2017 前端面试准备 - 收藏集 - 掘金
  • 2017前端实习生面试总结
  • android 一些 utils
  • Angular 响应式表单 基础例子
  • go append函数以及写入
  • Java面向对象及其三大特征
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • Lucene解析 - 基本概念
  • 创建一个Struts2项目maven 方式
  • 给初学者:JavaScript 中数组操作注意点
  • 构造函数(constructor)与原型链(prototype)关系
  • 后端_MYSQL
  • 记一次和乔布斯合作最难忘的经历
  • 开源SQL-on-Hadoop系统一览
  • 山寨一个 Promise
  • 一道闭包题引发的思考
  •  一套莫尔斯电报听写、翻译系统
  • HanLP分词命名实体提取详解
  • mysql面试题分组并合并列
  • ​configparser --- 配置文件解析器​
  • ​HTTP与HTTPS:网络通信的安全卫士
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #NOIP 2014#Day.2 T3 解方程
  • (1)(1.9) MSP (version 4.2)
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (Oracle)SQL优化基础(三):看懂执行计划顺序
  • (SpringBoot)第七章:SpringBoot日志文件
  • (二十九)STL map容器(映射)与STL pair容器(值对)
  • (翻译)terry crowley: 写给程序员
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (附源码)计算机毕业设计ssm电影分享网站
  • (微服务实战)预付卡平台支付交易系统卡充值业务流程设计
  • (游戏设计草稿) 《外卖员模拟器》 (3D 科幻 角色扮演 开放世界 AI VR)
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • .env.development、.env.production、.env.staging