这是我参与更文挑战的第23天,活动详情查看: 更文挑战
前言
是什么催生了Spring Cloud Stream? 谈到说到微服务,我们不可避免的,就会聊到消息中间件,RabbitMQ、ActiveMQ、RocketMQ、Kafka等等,总的来说,这些消息中间件是为了将消息进行传递,虽然目的的传递消息,但是不同的中间件有着不同的消息结构定义,这时,Spring Cloud Stream出现了,它主要是屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程模型。
什么是Spring Cloud Stream?
先简单了解与Spring Cloud Stream相关的两个项目:Spring Messaging 和 Spring Integration
Spring Messaging
Spring Messaging是Spring源码中的一个模块,它的结构为:
网上博客除了下面图片列出的结构,还有一个base(在目前的Spring message源码中目录下,小编暂时没找到,等发现再来补上)
base作用
- 定义了消息Message(MessageHeader和body),message由两部分组成:Header和Payload
- MessageHandler:一个处理消息的约定
- MessageChannel:发送消息
其它模块
- converter模块:转换器,对消息转换提供支持
- core模块:核心core模块提供消息的模板方法
- handler模块:处理模块
- Simp模块:包含诸如STOMP协议的简单消息协议的通用支持
- support模块:提供了Message的实现,及创建消息的MessageBuilder和获取消息头的MessageHeaderAccessor,还有各种不同的MessageChannel实现和channel interceptor支持
- tcp模块:提供了通过TcpOperations建立tcp connection、通过TcpConnectionHandler处理消息和通过TcpConnectionf发送消息的抽象及实现;另一方面包含了对基于Reactor的tcp 消息支持。
Spring Integration
Spring Integration 提供了 Spring 编程模型的扩展用来支持企业集成模式(Enterprise Integration Patterns),是对 Spring Messaging 的扩展。
- 消息的路由 MessageRoute
- 消息的分发 MessageDispatcher
- 消息的过滤 Filter
- 消息的转换 Transformer
- 消息的聚合 Aggregator
- 消息的分割 Splitter
- 提供了 MessageChannel 和MessageHandler 的实现
Spring Cloud Stream
在 Spring Integration 的基础上进行了封装,提出了 Binder, Binding, @EnableBinding, @StreamListener 等概念;
Spring Cloud Stream的使用逻辑?
应用程序通过inputs或者 outputs 来与Spring Cloud Stream中binder对象交互
- 通过我们配置来binding(绑定)
- Spring Cloud Stream 的binder对象负责与消息中间件交互
- 通过使用Spring Integration来连接消息代理中间件以实现消息事件驱动
使用效果
通过定义绑定器Binder作为中间层,实现了应用程序与消息中间件细节之间的隔离
Spring Cloud Stream实战
创建 Spring Cloud Stream 消息发送服务模块
pom内容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>study</artifactId>
<groupId>brief.talk.spring.cloud</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-stream-rabbitmq-provider</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<!--基础配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
yml
server:
port: 8500
spring:
application:
name: cloud-stream-provider
cloud:
stream:
binders: # 在此处配置要绑定的rabbitmq的服务信息;
defaultRabbit: # 表示定义的名称,用于于binding整合
type: rabbit # 消息组件类型
environment: # 设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
bindings: # 服务的整合处理
output: # 这个名字是一个通道的名称
destination: studyExchange # 表示要使用的Exchange名称定义
content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
binder: defaultRabbit # 设置要绑定的消息服务的具体设置
eureka:
client: # 客户端进行Eureka注册的配置
service-url:
defaultZone: http://localhost:8080/eureka
instance:
lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
instance-id: send-8500.com # 在信息列表时显示主机名称
prefer-ip-address: true # 访问的路径变为IP地址
业务接口及实现
public interface MessageProvider {
public String send();
}
public class MessageProviderImpl implements MessageProvider {
@Resource
private MessageChannel output; // 消息发送管道
@Override
public String send()
{
String serial = UUID.randomUUID().toString();
output.send(MessageBuilder.withPayload(serial).build());
System.out.println("发送数据serial = " + serial);
return null;
}
}
控制层实现
@RestController
public class SendMessageController
{
@Resource
private MessageProvider messageProvider;
@GetMapping(value = "/sendMessage")
public String sendMessage() {
return messageProvider.send();
}
}
创建 Spring Cloud Stream 消息接收服务模块
pom与yml同息发送服务模块一样,port改为其它的,比如8501
控制层实现
@Component
@EnableBinding(WriteBuffer.Sink.class)
public class ReceiveMessageListenerController
{
@Value("${server.port}")
private String serverPort;
@StreamListener(Sink.INPUT)
public void input(Message<String> message)
{
System.out.println("消费者端口号为" + serverPort +",----->接受到的消息: "+message.getPayload()+"\t port: "+serverPort);
}
}
今日小结
今天主要讲了与Spring Cloud Stream相关的Spring Messaging 和 Spring Integration,以及Spring Cloud Stream的实战!