Spring Cloud Stream 集成 MQTT 详细教程(含多组 Input/Output Channel,使用 `@Input`/`@Output`)

Spring Cloud Stream 集成 MQTT 详细教程(含多组 Input/Output Channel,使用 @Input/@Output

一、环境准备
  1. 安装 MQTT Broker

    • 推荐使用 EMQXMosquitto,确保服务运行在 tcp://localhost:1883
  2. 创建 Spring Boot 项目

    • 使用 Spring Initializr 生成项目,选择依赖:
      • Spring Cloud Stream
      • MQTT Binder
二、添加 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 查看通道状态。
九、最佳实践
  1. 主题设计

    • 使用层次化主题(如 device/{deviceId}/status)。
    • 避免通配符滥用(#+)。
  2. QoS 配置

    • 关键消息(如告警)使用 QoS=1QoS=2
    • 非关键数据使用 QoS=0 降低延迟。
  3. 错误处理

    • 为每个通道定义独立的 ErrorHandler
      @Bean
      public ErrorHandler deviceErrorHandler() {
          return ex -> System.err.println("设备通道错误: " + ex.getMessage());
      }
      
  4. 动态路由

    • 结合 StreamBridgeRouter 函数实现复杂路由逻辑:
      @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 客户端。
  • 弹性路由:结合配置和代码逻辑,灵活处理不同业务场景的消息流。
  • 高可扩展性:新增通道只需修改配置和添加注解,无需重构代码。

适用于需要对接海量设备或复杂事件驱动的物联网应用场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值