Spring Cloud Stream 集成 MQTT 详细教程(含多组 Input/Output Channel,使用 @Input
/@Output
)
一、环境准备
-
安装 MQTT Broker
-
创建 Spring Boot 项目
- 使用 Spring Initializr 生成项目,选择依赖:
- Spring Cloud Stream
- MQTT Binder
- 使用 Spring Initializr 生成项目,选择依赖:
二、添加 Maven 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-mqtt</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
</dependency>
三、配置多组 Input/Output Channel
在 application.yml
中定义多个输入/输出通道,绑定到不同的 MQTT 主题:
spring:
cloud:
stream:
binders:
mqtt-binder:
type: mqtt
environment:
spring:
mqtt:
url: tcp://localhost:1883
username: admin
password: public
client-id: multi-channel-client-${random.value}
default-topic: test/#
completion-timeout: 3000
bindings:
# 输入通道1:设备状态
device-status-input:
destination: test/device/status
group: device-group
binder: mqtt-binder
# 输入通道2:传感器数据
sensor-data-input:
destination: test/sensor/data
group: sensor-group
binder: mqtt-binder
# 输出通道1:设备控制指令
device-control-output:
destination: test/device/control
binder: mqtt-binder
# 输出通道2:告警通知
alert-output:
destination: test/alert
binder: mqtt-binder
四、定义 Input/Output 通道接口
使用 @Input
和 @Output
注解定义通道接口,实现代码与配置的解耦。
1. 输入通道接口
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.stereotype.Component;
@Component
public class MqttInputChannels {
// 绑定到 device-status-input 通道
@Input("device-status-input")
public SubscribableChannel deviceStatusInput() {
return new DirectChannel();
}
// 绑定到 sensor-data-input 通道
@Input("sensor-data-input")
public SubscribableChannel sensorDataInput() {
return new DirectChannel();
}
}
2. 输出通道接口
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
import org.springframework.stereotype.Component;
@Component
public class MqttOutputChannels {
// 绑定到 device-control-output 通道
@Output("device-control-output")
public MessageChannel deviceControlOutput() {
return new DirectChannel();
}
// 绑定到 alert-output 通道
@Output("alert-output")
public MessageChannel alertOutput() {
return new DirectChannel();
}
}
五、实现消息消费者
通过 @StreamListener
或函数式编程监听输入通道。
1. 监听设备状态通道
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
@Component
public class DeviceStatusListener {
@StreamListener("device-status-input")
public void handleDeviceStatus(@Payload String status) {
System.out.println("[设备状态通道] 接收状态: " + status);
// 处理设备状态逻辑(如更新数据库)
}
}
2. 监听传感器数据通道
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
@Component
public class SensorDataListener {
@StreamListener("sensor-data-input")
public void handleSensorData(@Payload String data) {
System.out.println("[传感器数据通道] 接收数据: " + data);
// 处理传感器数据逻辑(如数据分析)
}
}
六、实现消息生产者
通过注入 MqttOutputChannels
接口发送消息到输出通道。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
@Component
public class MqttMessageSender {
@Autowired
private MqttOutputChannels mqttOutputChannels;
// 发送设备控制指令
public void sendDeviceControl(String command) {
Message<String> message = MessageBuilder.withPayload(command)
.setHeader("mqtt_qos", 1)
.build();
mqttOutputChannels.deviceControlOutput().send(message);
}
// 发送告警通知
public void sendAlert(String alert) {
Message<String> message = MessageBuilder.withPayload(alert)
.setHeader("mqtt_qos", 1)
.build();
mqttOutputChannels.alertOutput().send(message);
}
}
七、高级配置
1. 持久化会话
spring:
mqtt:
client:
clean-session: false # 启用持久化会话
2. 自定义连接工厂
@Configuration
public class MqttConfig {
@Bean
public MqttPahoClientFactory mqttClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
MqttConnectOptions options = new MqttConnectOptions();
options.setServerURIs(new String[]{"tcp://localhost:1883"});
options.setUserName("admin");
options.setPassword("public".toCharArray());
options.setAutomaticReconnect(true);
options.setConnectionTimeout(10);
factory.setConnectionOptions(options);
return factory;
}
}
3. 消息转换器
@Configuration
public class MessageConverterConfig {
@Bean
public MqttPahoMessageDrivenChannelAdapter.MessageConverter messageConverter() {
return new DefaultPahoMessageConverter() {
@Override
public Object convertFrom(MqttPahoMessageDrivenChannelAdapter.MqttPahoMessageData data) {
String payload = super.convertFrom(data).toString();
// 自定义消息解析逻辑(如JSON转对象)
return "Processed: " + payload;
}
};
}
}
八、测试与调试
1. 发送测试消息
@Autowired
private MqttMessageSender mqttMessageSender;
public void testSend() {
// 发送设备控制指令
mqttMessageSender.sendDeviceControl("REBOOT");
// 发送告警通知
mqttMessageSender.sendAlert("Temperature Exceeded!");
}
2. 监控消息流
- 启用 Actuator 端点:
management: endpoints: web: exposure: include: bindings, binders
- 访问
http://localhost:8080/actuator/bindings
查看通道状态。
九、最佳实践
-
主题设计:
- 使用层次化主题(如
device/{deviceId}/status
)。 - 避免通配符滥用(
#
和+
)。
- 使用层次化主题(如
-
QoS 配置:
- 关键消息(如告警)使用
QoS=1
或QoS=2
。 - 非关键数据使用
QoS=0
降低延迟。
- 关键消息(如告警)使用
-
错误处理:
- 为每个通道定义独立的
ErrorHandler
:@Bean public ErrorHandler deviceErrorHandler() { return ex -> System.err.println("设备通道错误: " + ex.getMessage()); }
- 为每个通道定义独立的
-
动态路由:
- 结合
StreamBridge
和Router
函数实现复杂路由逻辑:@Bean public Function<Message<String>, Message<String>> dynamicRouter() { return message -> { String payload = message.getPayload(); if (payload.contains("error")) { return MessageBuilder.fromMessage(message) .setHeader("targetChannel", "alert-output") .build(); } else { return MessageBuilder.fromMessage(message) .setHeader("targetChannel", "device-control-output") .build(); } }; }
- 结合
十、总结
通过 @Input
和 @Output
注解,Spring Cloud Stream 实现了配置与代码的解耦,使多通道 MQTT 集成更加清晰和可维护。核心优势包括:
- 统一编程模型:通过注解定义通道,无需直接操作 MQTT 客户端。
- 弹性路由:结合配置和代码逻辑,灵活处理不同业务场景的消息流。
- 高可扩展性:新增通道只需修改配置和添加注解,无需重构代码。
适用于需要对接海量设备或复杂事件驱动的物联网应用场景。