目前 Spring Cloud Stream 支持两种中间件 rabbitMQ, kafka.
1. 简单利用cloud Stream进行收发信息
1.1 首先启动 rabbitmq作为mq
rabbitmqServer.sh start
1.2 新建项目,引入对应的POM依赖
org.springframework.cloud
spring-cloud-stream-binder-rabbit
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
1.3 增加配置文件
#注意管道的名字需要变化, example-topic-output/example-topic-input
spring.cloud.stream.bindings.example-topic-output.destination=chenhuallong
spring.cloud.stream.bindings.example-topic-input.destination=chenhuallong
spring.cloud.stream.bindings.input.group=Service-lemon
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
1.4 Steam 中Binder的定位,Exchange的定位
steam主要的进行隔离的架构如下:
stream中默认已经有 Source.class sink.class两个 交换器了。
1.5 自己定义exchagne
/**
* 自定义自己的通道queue
*/
public interface LemonMessageTopic {
String LEMON_OUTPUT = "example-topic-output";
String LEMON_INPUT = "example-topic-input";
@Output(LEMON_OUTPUT)
MessageChannel output();
@Input(LEMON_INPUT)
SubscribableChannel input();
}
1.5.1 在主类上将exchange进行注入
@EnableBinding(LemonMessageTopic.class)
@SpringBootApplication
public class DemoSpringcloudStreamApplication {
public static void main(String[] args) {
SpringApplication.run(DemoSpringcloudStreamApplication.class, args);
}
}
1.6 定义收取消息的代码类
@Component
public class MessageReceiver {
@StreamListener(LemonMessageTopic.LEMON_INPUT)
public void receive(Object message){
System.out.println("messageReceive :" +message.toString());
}
}
1.7 定义发送消息的代码类
@RestController
public class MessageController {
@Autowired
private LemonMessageTopic topic;
@GetMapping("/send")
public Object sendMessage() {
String message = "hello ,this is my first message";
topic.output().send(org.springframework.messaging.support.MessageBuilder.withPayload(message).build());
return "success";
}
}
1.8 观察rabbitmQ
2. 使用消息订阅模式
2.1 再新建一个项目,和上一个完全一样,然后启动
2.2 发送一条信息,观察两个项目都可以收到
3. 消息分组
为了防止 这种消息被所有人都消费掉,所以采用消息分组,只有在同一个消费组中,且同一个消费组中,只能有一个实例进行消费,保证不会多次消费。
spring.cloud.stream.bindings.input.group
在准备消费同一信息的实例中,增加相同的分组
spring.cloud.stream.bindings.example-topic-input.group=Service-lemon
后续就变成了遍历进行轮询消化对应的接口
4. 消息分区
对于一些特殊场景,除了要保证单一实例消费之外,还希望那些具备相同特征的消息都能够被同一个实例进行消费。这时候我们就需要对消息进行分区处理
4.1 消费端需要更改的配置如下
# 打开消费者分区功能
spring.cloud.stream.bindings.input.consumer.partitioned=true
#当前消费者的总实例数量
spring.cloud.stream.instanceCount=2
# 当前实例索引号
spring.cloud.stream.instanceIndex=0
4.2 修改生产者的配置
# 通过消息规则配置SPEL生成分区间
spring.cloud.stream.bindings.output.producer.partitionKeyExpression=payload
# 指定消息分区的数量
spring.cloud.stream.bindings.output.producer.partitionCount=2
5. 通过消息内容分发给不同消费处理逻辑
5.1 生产端代码改造
@GetMapping("/sendMessage")
public String messageWithMQ(@RequestParam String message) {
testTopic.output().send(MessageBuilder.withPayload(message).setHeader("version", "1.0").build());
testTopic.output().send(MessageBuilder.withPayload(message).setHeader("version", "2.0").build());
return "ok";
}
5.2 消费端代码改造
@StreamListener(value = TestTopic.INPUT, condition = "headers['version']=='1.0'")
public void receiveV1(String payload, @Header("version") String version) {
log.info("Received v1 : " + payload + ", " + version);
}
@StreamListener(value = TestTopic.INPUT, condition = "headers['version']=='2.0'")
public void receiveV2(String payload, @Header("version") String version) {
log.info("Received v2 : " + payload + ", " + version);
}
6. 自动失败重试机制
默认情况下Spring Cloud Stream会重试3次,我们也可以通过配置的方式修改这个默认配置,比如下面的配置可以将重试次数调整为1次。
spring.cloud.stream.bindings.example-topic-input.consumer.max-attempts=1