Spring Cloud Stream微服务消息框架
简介
随着近些年微服务在国内的盛行,消息驱动被提到的越来越多。主要原因是系统被拆分成多个模块后,一个业务往往需要在多个服务间相互调用,不管是采用HTTP还是RPC都是同步的,不可避免快等慢的情况发生,系统性能上很容易遇到瓶颈。在这样的背景下,将业务中实时性要求不是特别高且非主干的部分放到消息队列中是很好的选择,达到了异步解耦的效果。
目前消息队列有很多优秀的中间件,目前使用较多的主要有 RabbitMQ,Kafka,RocketMQ 等,这些中间件各有优势,有的对 AMQP(应用层标准高级消息队列协议)支持完善,有的提供了更高的可靠性,有的对大数据支持良好,同时各种消息中间件概念不统一,使得选择和使用一款合适的消息中间件成为难题。Spring跳出来给出了解决方案:Spring Cloud Stream,使用它可以很方便高效的操作消息中间件,程序员只要关心业务代码即可,目前官方支持 RabbitMQ,Kafka两大主流MQ,RocketMQ 则自己提供了相应支持。
首先看一下Spring Cloud Stream做了什么,如下图所示,框架目前官方把消息中间件抽象成了 Binder,业务代码通过进出管道连接 Binder,各消息中间件的差异性统一交给了框架处理,程序员只需要了解框架的抽象出来的一些统一概念即可
- Binder(绑定器):RabbitMQ,Kafka等中间件服务的封装
- Channel(管道):也就是图中的 inputs 和 outputs 所指区域,是应用程序和 Binder 的桥梁
- Gourp(消费组):由于微服务会部署多实例,为了保证只被服务的一个实例消费,可以通过配置,把实例都绑到同一个消费组
- Partitioning (消息分区):如果某一类消息只想指定给服务的固定实例消费,可以使用分区实现

Spring Cloud Stream将业务代码和消息中间件解耦,带来的好处可以从下图很直观的感受到,很简洁的代码,我们便能从RabbitMQ中接受消息然后经过业务处理再向Kafka发送一条消息,只需要更改相关配置就能快速改变系统行为。

细心的读者可能会好奇,上图的代码只是注入了一个简单的 Function 而已,实际上,Spring Cloud Stream3.0后集成了Spring Cloud Function框架 ,提倡函数式的风格,弃用先前版本基于注解的开发方式。Spring Cloud Function是 Serverless 和 Faas 的产物,强调面向函数编程,一份代码各云平台运行,和Spring Cloud Stream一样也是解决了基础设施的差异性问题,通过强大的自动装配机制,可以根据配置自动暴露 HTTP 服务或者消息服务,并且同时支持命令式和响应式编程模式,可以说是很强大了。下面通过一个简单的例子来理解下上图的代码和框架的使用把。
简单案例
模拟一个简单的下单,收到订单之后处理完,返回成功,然后发送消息给库存模块,库存模块再发送消息给报表模块
项目地址
项目结构

项目依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
表单
@Data
public class OrderForm {
private String productName;
}
消息管道注册
@Configuration
@Slf4j
public class MessageQueueConfig {
@Bean
public Function<OrderForm, OrderForm> inventory() {
return orderForm -> {
log.info("Inventory Received Message: " + orderForm);
return orderForm;
};
}
@Bean
public Consumer<OrderForm> report() {
return orderForm -> {
log.info("Report Received Message: " + orderForm);
};
}
}
Controller
@Slf4j
@RestController
public class OrderController {
@Autowired
private BeanFactoryChannelResolver resolver;
@PostMapping("order")
public String order(@RequestBody OrderForm orderForm) {
log.info("Received Request " + orderForm);
resolver.resolveDestination("inventory-in-0").send(new GenericMessage<>(orderForm));
return "success";
}
}
配置
框架会按照中间件默认端口去连接,这里自定义了一个名为myLocalRabbit的类型是RabbitMQ的Binder配置,bindings下面 inventory-in-0 是通道名,接受inventory主题(对应RabbitMQ的ExChange)的消息,然后处理完通过 inventory-out-0 通道发送消息到 report 主题, report-in-0通道负责接受report主题的消息。
注:通道名=注册的 function 方法名 + in或者out + 参数位置(详见注释)
spring:
cloud:
stream:
# 配置消息中间件信息
binders:
myLocalRabbit:
type: rabbit
environment:
spring:
rabbitmq:
host: localhost
port: 31003
username: guest
password: guest
virtual-host: /
# 重点,如何绑定通道,这里有个约定,开头是函数名,in表示消费消息,out表示生产消息,最后的数字是函数接受的参数的位置,destination后面为订阅的主题
# 比如Function<Tuple2<Flux<String>, Flux<Integer>>, Flux<String>> gather()
# gather函数接受的第一个String参数对应 gather-in-0,第二个Integer参数对应 gather-in-1,输出对应 gather-out-0
bindings:
inventory-in-0:
destination: inventory
inventory-out-0:
destination: report
report-in-0:
destination: report
# 注册声明的三个函数
function:
definition: inventory;report
测试
POST http://localhost:8080/order
Content-Type: application/json
{
"productName": "999"
}
结果
POST http://localhost:8080/order
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 7
Date: Sat, 30 May 2020 15:27:56 GMT
Keep-Alive: timeout=60
Connection: keep-alive
success
Response code: 200; Time: 56ms; Content length: 7 bytes
后台日志
可以看到消息成功发送到了库存和报表服务
2020-05-30 23:27:56.956 INFO 8760 --- [nio-8080-exec-1] c.e.springcloudstream.OrderController : Received Request OrderForm(productName=999)
2020-05-30 23:27:56.956 INFO 8760 --- [nio-8080-exec-1] o.s.i.h.s.MessagingMethodInvokerHelper : Overriding default instance of MessageHandlerMethodFactory with provided one.
2020-05-30 23:27:56.957 INFO 8760 --- [nio-8080-exec-1] c.e.s.MessageQueueConfig : Inventory Received Message: OrderForm(productName=999)
2020-05-30 23:27:56.958 INFO 8760 --- [nio-8080-exec-1] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: [localhost:31003]
2020-05-30 23:27:56.964 INFO 8760 --- [nio-8080-exec-1] o.s.a.r.c.CachingConnectionFactory : Created new connection: rabbitConnectionFactory.publisher#6131841e:0/SimpleConnection@192fe472 [delegate=amqp://guest@127.0.0.1:31003/, localPort= 2672]
2020-05-30 23:27:56.965 INFO 8760 --- [nio-8080-exec-1] o.s.amqp.rabbit.core.RabbitAdmin : Auto-declaring a non-durable, auto-delete, or exclusive Queue (inventory.anonymous.wtaFwHlNRkql5IUh2JCNAA) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
2020-05-30 23:27:56.965 INFO 8760 --- [nio-8080-exec-1] o.s.amqp.rabbit.core.RabbitAdmin : Auto-declaring a non-durable, auto-delete, or exclusive Queue (report.anonymous.SJgpJKiJQf2tudszgf623w) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
2020-05-30 23:27:56.979 INFO 8760 --- [f2tudszgf623w-1] o.s.i.h.s.MessagingMethodInvokerHelper : Overriding default instance of MessageHandlerMethodFactory with provided one.
2020-05-30 23:27:56.980 INFO 8760 --- [f2tudszgf623w-1] c.e.s.MessageQueueConfig : Report Received Message: OrderForm(productName=999)
Spring Cloud Stream微服务消息框架的更多相关文章
- spring Boot+spring Cloud实现微服务详细教程第二篇
上一篇文章已经说明了一下,关于spring boot创建maven项目的简单步骤,相信很多熟悉Maven+Eclipse作为开发常用工具的朋友们都一目了然,这篇文章主要讲解一下,构建spring bo ...
- 【微服务】使用spring cloud搭建微服务框架,整理学习资料
写在前面 使用spring cloud搭建微服务框架,是我最近最主要的工作之一,一开始我使用bubbo加zookeeper制作了一个基于dubbo的微服务框架,然后被架构师否了,架构师曰:此物过时.随 ...
- Spring Cloud构建微服务架构(三)消息总线
注:此文不适合0基础学习者直接阅读,请先完整的将作者关于微服务的博文全部阅读一遍,如果还有疑问,可以再来阅读此文,地址:http://blog.csdn.net/sosfnima/article/d ...
- 干货|基于 Spring Cloud 的微服务落地
转自 微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务.但如果要将微服务架构运用到生产项目上,并且能够发挥该架构模式的重要作用,则需要微服务框架的支持. 在Java生态圈,目前使用较多的 ...
- 基于Spring Cloud的微服务落地
微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务.但如果要将微服务架构运用到生产项目上,并且能够发挥该架构模式的重要作用,则需要微服务框架的支持. 在Java生态圈,目前使用较多的微服务 ...
- Spring Cloud与微服务构建:Spring Cloud简介
Spring Cloud简介 微服务因该具备的功能 微服务可以拆分为"微"和"服务"二字."微"即小的意思,那到底多小才算"微&q ...
- 基于Spring Boot和Spring Cloud实现微服务架构学习
转载自:http://blog.csdn.net/enweitech/article/details/52582918 看了几周Spring相关框架的书籍和官方demo,是时候开始总结下这中间的学习感 ...
- 基于Spring Boot和Spring Cloud实现微服务架构学习--转
原文地址:http://blog.csdn.net/enweitech/article/details/52582918 看了几周spring相关框架的书籍和官方demo,是时候开始总结下这中间的学习 ...
- 基于Spring Boot和Spring Cloud实现微服务架构
官网的技术导读真的描述的很详细,虽然对于我们看英文很费劲,但如果英文不是很差,请选择沉下心去读,你一定能收获好多.我的学习是先从Spring boot开始的,然后接触到微服务架构,当然,这一切最大的启 ...
随机推荐
- shell之路 shell核心语法【第一篇】shell初识
shell简介 1.Shell是Unix的脚本语言,是与 Unix/Linux 交互的工具,shell使用的熟练程度反映了用户对Unix/Linux使用的熟练程度 2.Shell是系统命令+程序逻辑的 ...
- C# 数据操作系列 - 1. SQL基础操作
0.前言 前篇介绍了一些数据库的基本概念和以及一些常见的数据库,让我们对数据库有了一个初步的认识.这一篇我们将继续为C#数据操作的基础填上一个空白-SQL语句. SQL(Structured Quer ...
- 架构设计 | 分布式系统调度,Zookeeper集群化管理
本文源码:GitHub·点这里 || GitEE·点这里 一.框架简介 1.基础简介 Zookeeper基于观察者模式设计的组件,主要应用于分布式系统架构中的,统一命名服务.统一配置管理.统一集群管理 ...
- Viterbi-Algorithm(维特比)算法
CSDN博客:皮乾东 知乎:Htrying 微博:Htring的微博 微信公众号:自然语言处理爱好者(ID:NLP_lover) 文章来自:<数学之美> Viterbi-Algor ...
- ThinkPad BIOS
ThinkPad-BIOS 如有问题指出 ~谢谢
- Js调用Android回调处理
通常在混合app中经常会使用js调用native的方法,一般是: window.nativeApp.call(XXX); 直接调用native方法,对于简单的处理倒是可以,如果需要回调呢?期待的方式是 ...
- 分布式文件存储库MinIO可还行?
在传统的单体应用架构中,一个应用程序对应一台服务器,提供单进程服务. 但是随着业务的升级,技术的更新迭代,分布式.集群架构.微服务等现已俨然成为主流. 几乎所有的项目都会与文件挂钩,例如OA系统的报表 ...
- Navicat for MySQL数据库管理工具安装和破解
Navicat for MySQL官方下载地址:https://www.navicat.com/en/download/navicat-for-mysql 1.下载后安装 navicat110_mys ...
- JS的函数和对象三
复习 判断是否含有某个属性 对象.属性名 === undefined 对象.hasOwnProperty('属性名') '属性名' in 对象 方法 { say:function(){ this ...
- antd自定义样式主题
参考网址: https://blog.csdn.net/focusdroid/article/details/85381042 链接: 这篇文章:(#*3 and #*4)借鉴@钱锋这位童鞋,如有侵权 ...