Spring Cloud Stream是一个用来为微服务应用构建消息驱动能力的轻量级框架。
它可以基于Spring Boot来创建独立的、可用于生产的Spring应用程序。它通过使用Spring Integration来连接消息代理中间件以实现消息事件驱动的微服务应用。
概念理解
Spring Cloud Stream为一些供应商的消息中间件产品提供了个性化的自动化配置实现,并且引入了发布-订阅、消费组以及消息分区这三个核心概念。
从组件结构上,Spring Cloud Stream中有以下几个重要概念:
- Destination Binders: 目标绑定器,目标是指kafka还是RabbitMQ,绑定器就是封装了目标中间件的包。
- Destination Bindings:外部消息传递系统和应用程序之间的桥梁,提供消息的“生产者”和“消费者”(由目标绑定器创建)
- Message:一种规范化的数据结构,生产者和消费者基于这个数据结构通过外部消息系统与目标绑定器和其他应用程序通信。
通过使用Spring Cloud Stream,可以有效地简化开发人员对消息中间件的使用复杂度,让系统开发人员可以有更多的精力专注于核心业务逻辑的处理。
编码实践
本文以rabbitmq为消息队列,所以先在本地搭建好rabbitmq环境,然后装好rabbitmq-management插件,这样就可以访问web UI界面了,默认是15672端口。
github 代码地址:https://github.com/guzhangyu/learn-spring-cloud/tree/master/spring-cloud-stream
1、引用rabbitmq的stream包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
2、在application.yml中增加配置
spring:
application:
name: spring_cloud_stream_rabbitmq
cloud:
stream:
bindings:
demo_input:
group: service-a
destination: demo
binder: local_rabbit
demo_output:
group: service-a
destination: demo
binder: local_rabbit
binders:
local_rabbit:
type: rabbit
environment:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
spring.cloud.stream.binders配置了一个binder,命名为local_rabbit。
spring.cloud.stream.bindings对应上面提到的 Destination Bindings。这里可以配置多个input或者output,分别表示消息的接收通道和发送通道,对应到rabbitmq上就是不同的exchange。
可以看到demo_input、demo_output对应的destination是相同的,也就是对应相同的exchange。
还可以设置group,因为服务很可能不止一个实例,如果启动多个实例,那么没必要每个实例都消费同一个消息,只要把功能相同的实例的group设置为同一个,那么就会只有一个实例来消费消息,避免重复消费的情况。
如果设置了group,那么group名称就会成为queue的名称,如果没有设置group,那么queue就会根据destination + 随机字符串的方式命名。
3、定义消息接收通道和消息处理者
接收通道定义,定义了一个SubscribableChannel类型的input()方法,表示订阅一个消息的方法,并用@Input注解标识,并且指定了 binding的名称为demo_input。
interface DemoInput {
String DEMO_INPUT = "demo_input";
@Input(DEMO_INPUT)
SubscribableChannel input();
}
创建消息的处理者,用来订阅消息并对消息进行处理。
加上注解@EnableBinding(DemoInput.class),表明启用stream,并指定定义的Channel定义接口类。
@EnableBinding(DemoInput.class)
public class DemoReceiver {
private static Logger logger = LoggerFactory.getLogger(DemoReceiver.class);
@StreamListener(DemoInput.DEMO_INPUT)
public void receive(Object payload) {
logger.info("Received: " + payload);
}
}
4、定义消息发送通道和消息的发送者
发送通道定义,定义了一个SubscribableChannel类型的output()方法,表示订阅一个消息的方法,并用@Output注解标识,并且指定了 binding的名称为demo_output。
interface DemoSender {
String DEMO_OUTPUT = "demo_output";
@Output(DEMO_OUTPUT)
MessageChannel output();
}
定义消息的发送者,用来发送消息。
加上注解@EnableBinding(DemoInput.class),表明启用stream,并指定定义的Channel定义接口类。
@SpringBootApplication
@EnableBinding(RabbitmqStreamApplication.DemoSender.class)
public class RabbitmqStreamApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(RabbitmqStreamApplication.class, args);
DemoSender demoSender = applicationContext.getBean(DemoSender.class);
demoSender.output().send(MessageBuilder.withPayload("fda").build());
}