什么是Spring Cloud Stream
一个用于构建消息驱动的微服务的框架
应用程序通过 inputs 或者 outputs 来与 Spring Cloud Stream 中binder 交互,通过我们配置来 binding ,而 Spring Cloud Stream 的 binder 负责与中间件交互。所以,我们只需要搞清楚如何与 Spring Cloud Stream 交互就可以方便使用消息驱动的方式
Spring Cloud Stream编程模型
- Destination Binder(目标绑定器)
- 与消息中间件通信的组件
- Destination Bindings(目标绑定)
- Binding是连接应用程序与消息中间件的桥梁,用于消息的消费和生产,有Binder创建
- Message(消息)
微服务集成了Stream,Stream的Destination Binder创建了两个Binding,左边的Binding连接Rabbit MQ,右边的MQ连接Kafka。 左边的Binding从Rabbit MQ处消费消息,然后经过Application处代码的处理,把处理结果传输给Kafka。【从Rabbit MQ处消费消息,然后经过处理,生产到Kafka】
使用Spring Cloud Stream 实现消息收发
编写生产者
添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>
注意groupId为com.alibaba.cloud,而不是org.springframework.cloud
添加注解
在启动类上添加**@EnableBinding注解,其中Source**用来发送消息
@SpringBootApplication
@EnableBinding(Source.class)
public class Study01Application {
public static void main(String[] args) {
SpringApplication.run(Study01Application.class, args);
}
}
添加配置
rocketmq.binder.name-server RocketMQ控制台地址 output 表示生产者,用于绑定一个topic投递消息 bindings.output.destination 指定topic
spring:
cloud:
stream:
rocketmq:
binder:
name-server: 127.0.0.1:9876
bindings:
# 生产者
output:
# 指定topic
destination: topic-stream
代码实现
注入Source接口,用来实现消息发送 MessageBuilder构建消息体
@Autowired
private Source source;
@GetMapping("test-stream")
public String testStream() {
this.source.output()
.send(
MessageBuilder
.withPayload("消息体")
.build()
);
return "testStream";
}
控制台查看
启动项目,请求之后,可以在RocketMQ控制台-消息页面看见topic为topic-stream的消息
编写消费者
添加依赖
同生产者
添加注解
@SpringBootApplication
@EnableBinding(Sink.class)
public class Study02Application {
public static void main(String[] args) {
SpringApplication.run(Study02Application.class, args);
}
}
添加配置
input表示消费者,用于绑定一个topic消费消息 destination指定topic,要与生产者的topic相对应.在使用RocketMQ时,group必填;使用其他MQ时,可以留空
spring:
cloud:
stream:
rocketmq:
binder:
name-server: 127.0.0.1:9876
bindings:
# 消费者
input:
# 指定topic,要与生产者的topic匹配
destination: topic-stream
# 根据业务指定
# 一定要设置,否则会启动报错
# 如果使用的是其他的MQ,可以留空
group: group-stream
代码实现
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class testStreamConsumer {
@StreamListener(Sink.INPUT)
public void receive(String messageBody) {
log.info("------>" + messageBody);
}
}
测试结果
Spring Cloud Stream自定义接口
在以上的例子中,我们发现只可以设置一个topic,这显然满足不了实际的生产需求,所以这个时候就需要用到stream的自定义接口来实现多个“input”和“output”绑定不同的topic了。
生产者发送消息时使用的是Source接口里的output方法,而消费者接收消息时使用的是Sink接口里的input方法,并且都需要配置到启动类的@EnableBinding注解里。所以实际上我们需要自定义接口的源码与这两个接口的源码几乎一致,只是名称有所不同而已,使用上也只是将Source和Sink改为自定义的接口即可。
自定义发送消息
自定义消息发送接口
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
/**
* 自定义发送消息接口
*/
public interface customizeSource {
String CUSTOMIZE_OUTPUT = "customize-output";
@Output(CUSTOMIZE_OUTPUT)
MessageChannel output();
}
修改注解
在启动类的**@EnableBinding**注解上添加刚刚自定义的消息发送接口
@EnableBinding({Source.class, customizeSource.class})
修改配置
注意customize-output的值一定要与自定义消息发送接口中**@Output**注解的值相同
cloud:
stream:
rocketmq:
binder:
name-server: 127.0.0.1:9876
bindings:
# 生产者
output:
# 指定topic
destination: topic-stream
customize-output:
destination: topic-stream-customize
代码实现
@Autowired
private CustomizeSource customizeSource;
@GetMapping("test-stream-customize")
public String testCustomizeStream() {
customizeSource.output()
.send(
MessageBuilder
.withPayload("消息体")
.build()
);
return "testStream";
}
验证
自定义接收消息
自定义消息接收接口
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;
/**
* 自定义消费消息接口
*/
public interface CustomizeSink {
String CUSTOMIZE_INPUT = "customize-input";
@Input(CUSTOMIZE_INPUT)
SubscribableChannel input();
}
修改注解
在启动类的**@EnableBinding**注解上添加刚刚自定义的消息接收接口
@EnableBinding({Sink.class, CustomizeSink.class})
修改配置
注意customize-input的值一定要与自定义消息发送接口中**@Input**注解的值相同
cloud:
stream:
rocketmq:
binder:
name-server: 127.0.0.1:9876
bindings:
# 消费者
input:
# 指定topic,要与生产者的topic匹配
destination: topic-stream
# 根据业务指定
# 一定要设置,否则会启动报错
# 如果使用的是其他的MQ,可以留空
group: group-stream
customize-input:
destination: topic-stream-customize
group: group-stream-customize
代码实现
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class CustomizeStreamConsumer {
@StreamListener(CustomizeSink.CUSTOMIZE_INPUT)
public void receive(String messageBody) {
log.info("------>自定义>" + messageBody);
}
}
验证
**PS:**总结来说,@EnableBinding注解的Source接口实现了发送消息,Sink接口实现了接收消息.而@EnableBinding还有一个Processor接口,Processor接口继承了Source接口和Sink接口,使用这个接口可以实现收发消息
package org.springframework.cloud.stream.messaging;
public interface Processor extends Source, Sink {
}