Table of Contents
1.stream-rabbitmq-provider8801 消息生产模块
2.stream-rabbitmq-consumer8802/8803 消息消费模块
1.Stream 介绍
https://spring.io/projects/spring-cloud-stream
Spring Cloud Stream 是一个用来为微服务应用构建消息驱动能力的框架。它可以基于 Spring Boot 来创建独立的、可用于生产的 Spring 应用程序。Spring Cloud Stream 为一些供应商的消息中间件产品提供了个性化的自动化配置实现,并引入了发布-订阅、消费组、分区这三个核心概念。通过使用 Spring Cloud Stream,可以有效简化开发人员对消息中间件的使用复杂度,让系统开发人员可以有更多的精力关注于核心业务逻辑的处理。但是目前 Spring Cloud Stream 只支持 RabbitMQ 和 Kafka 的自动化配置。
有时要使用ActiveMQ,有时要使用RabbitMQ,甚至还有RocketMQ以及Kafka,这之间的切换似乎很麻烦,我们很难,也没有太多时间去精通每一门技术。Spring Cloud Stream 屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程模型,通过绑定器Binder作为中间件,实现了应用程序与消息中间件细节的解耦。
框架及注解
2.案例实现
1.stream-rabbitmq-provider8801 消息生产模块
pom
<dependencies>
<!--stream-rabbit-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.ak.demo</groupId>
<artifactId>api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<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.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>
</dependency>
</dependencies>
yml
server:
port: 8801
spring:
application:
name: stream-provider
cloud:
stream:
binders: # 在此处配置要绑定的rabbitMQ的服务信息: Map
defaultRabbit: # 表示定义的名称,用于binding的整合
type: rabbit # 消息组件类型
environment: # 设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: localhost
# port: 5672 默认
username: guest
password: guest
bindings: # 服务的整合处理: Map
output: # 这个名字是一个通道的名称
destination: studyExchange # 表示要使用的exchange名称定义
content-type: application/json # 设置消息类型,本次为json,文本则设为text/plain
binder: defaultRabbit # 设置要绑定的消息服务的具体设置
eureka:
client:
register-with-eureka: true #表示向注册中心注册自己 默认为true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
instance:
lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
instance-id: send-8801.com # 在信息列表时显示主机名称
prefer-ip-address: true # 访问的路径变为IP地址
业务类代码
@EnableBinding(value = Source.class) //定义消息的推送管道
public class MessageProviderImpl implements IMessageProvider {
@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;
}
}
2.stream-rabbitmq-consumer8802/8803 消息消费模块
pom
同8801
yml
server:
port: 8802
spring:
application:
name: stream-consumer
cloud:
stream:
binders: # 在此处配置要绑定的rabbitMQ的服务信息: Map
defaultRabbit: # 表示定义的名称,用于binding的整合
type: rabbit # 消息组件类型
environment: # 设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: localhost
# port: 5672 默认
username: guest
password: guest
bindings: # 服务的整合处理: Map
input: # 这个名字是一个通道的名称
destination: studyExchange # 表示要使用的exchange名称定义
content-type: application/json # 设置消息类型,本次为json,文本则设为text/plain
binder: defaultRabbit # 设置要绑定的消息服务的具体设置
eureka:
client:
register-with-eureka: true #表示向注册中心注册自己 默认为true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
instance:
lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
instance-id: send-8802.com # 在信息列表时显示主机名称
prefer-ip-address: true # 访问的路径变为IP地址
业务类代码
@EnableBinding(value = Sink.class)
@Component
public class ReceiveMessageController {
@Value("${server.port}")
private String serverPort;
@StreamListener(value = Sink.INPUT)
public void input(Message<String> message) {
System.out.println("消费者1,-------" + message.getPayload() + "\t port:" + serverPort);
}
}
3.消息重复消费与持久化
上面8802、8803同时收到信息,但实际生产中,这两个服务可能是同一个库存服务,就导致重复扣减库存。
要实现:不同的组存在重复消费,相同的组之间竞争消费,即把同一功能服务归为同一个组。
8802、8803加上:group: orderGroupA
bindings: # 服务的整合处理: Map
input: # 这个名字是一个通道的名称
destination: studyExchange # 表示要使用的exchange名称定义
content-type: application/json # 设置消息类型,本次为json,文本则设为text/plain
binder: defaultRabbit # 设置要绑定的消息服务的具体设置
group: orderGroupA
持久化
把8802 去除 group: orderGroupA,关闭8802、8803,8801发送消息,启动8802没有收到,启动8803收到信息。