【EMQX实践】SpringBoot集成EMQX客户端组件

Spring Boot是Spring框架的一个扩展,旨在简化Spring应用的初始搭建和开发过程。它提供了大量的自动配置和可插拔的组件,使得开发人员能够快速构建基于Java的应用程序。

  • 快速集成:通过将EMQX客户端集成到Spring Boot应用中,可以快速地实现物联网消息的发布和订阅功能。这种集成方式利用了Spring Boot的自动配置和依赖注入特性,使得代码的编写和维护更加简单。
  • 灵活性:Spring Boot和EMQX的集成提供了高度的灵活性。开发人员可以根据项目的需求选择合适的MQTT客户端库(如Paho MQTT客户端库),方便在应用程序中进行使用。
  • 统一管理:统一管理EMQX链接配置和Maven版本是确保项目稳定性和可维护性的重要手段。

组件设计

源码地址Gitee

代码结构

mqtt组件 (1).png

组件主要分为四部分

MQTT客户端上下文:

  • 连接管理:管理MQTT连接及断开连接功能。
  • 订阅列表:客户端订阅的所有主题及其对应的QoS(服务质量)级别。
  • 推送消息:发送消息到EMQX中。

MQTT配置信息

  • 包括MQTT代理的地址、端口、客户端ID、用户名、密码、订阅topic等。

MQTT消息监听接口

  • 监听topic。
  • 处理消息接口。

MQTT消息推送

  • 长链接的消息推送入口。
  • Http方式消息推送入口。

代码解析

UML图

mqtt组件 (2).png

模块介绍

MQTT客户端上下文(IMqttClient):

客户端上下文主要管理MQTT连接信息、MQTT连接、断开连接、消息推送、主题订阅等。

public interface IMqttClient {

    MqttClientApp connect();

    boolean isConnect();

    boolean disconnect();

    MqttResp publish(MqttReq request);

    MqttConfig getMqttConfig();

}
创建MQTT客户端:

选择使用Vert.x的MQTT客户端作为客户端,因为Vert.x提供了高性能的事件驱动编程模型,非常适合处理像MQTT这样的异步消息协议。

this.mqttClient = MqttClient.create(vertx, createMqttClientOptions());

private MqttClientOptions createMqttClientOptions() {
        MqttClientOptions options = new MqttClientOptions();
        options.setClientId("micro-client-" + RandomStringUtils.randomAlphanumeric(17));
        options.setMaxMessageSize(100_000_000);
        options.setKeepAliveInterval(60);
        options.setPassword(mqttConfig.getPassword());
        options.setUsername(mqttConfig.getUsername());
        options.setSsl(mqttConfig.getListenerInfos().isSsl());
        options.setReconnectInterval(RECONNECT_INTERVAL);
        options.setReconnectAttempts(Integer.MAX_VALUE);
        return options;
    }

建立连接:
 mqttClient.connect(mqttConfig.getListenerInfos().getPort(), mqttConfig.getListenerInfos().getHost(),
                s -> {
                    if (s.succeeded()) {
                        log.info("IMqttClient connect success.");
                        subscribe();
                        countDownLatch.countDown();
                    } else {
                        log.error("IMqttClient connect fail: ", s.cause());
                        if (s.cause() != null) {
                            vertx.setTimer(RECONNECT_INTERVAL, handler -> this.start());
                        }
                    }
断开连接:
    public boolean disconnect() {
        if (!isConnect()) {
            log.warn("IMqttClient no connect");
            return false;
        }
        vertx.undeploy(deploymentID(), (handler) -> {
            if (handler.succeeded()) {
                log.info("undeploy success");
            } else {
                log.warn("undeploy fail, {}. ", handler.cause().getMessage(), handler.cause());
            }
        });
        return true;
    }
推送消息MqttResp publish(MqttReq request)
@Data
public class MqttReq extends Req {

    private String messageContent;

}

@Data
public class Req {

    protected String messageId = RandomStringUtils.randomNumeric(12);

    protected final Long createdTime = System.currentTimeMillis();

    protected String topic;

    private Integer qos;

    protected Map<String, Object> headers = Maps.newHashMap();

    protected Map<String, Object> data = Maps.newHashMap();

}
MQTT配置信息(MqttConfig):

MQTT代理的地址、端口、客户端ID、用户名、密码、订阅topic等

字段描述类型
address对外域名String
host内网IPString
portTCP端口Integer
username名称String
password密码String
subscribeTopics订阅topicList
MQTT消息推送(IMqttApi):

提供服务统一推送消息到brocker接口。包含了Http短连接、TCP长连接两种方式推送消息。

public interface IMqttApi {


    MqttResp httpPublish(MqttReq request);



    MqttResp tcpPublish(MqttReq request);
}

推送消息MqttReq参数说明:

字段描述类型是否必填
topic消息主题String
qos消息等级Integer
messageContent消息体String不为空,则下面的参数不传
messageId消息唯一idStringmessageContent为空时
createdTime时间戳LongmessageContent为空时
headers请求头Map<String, Object>messageContent为空时
data消息内容Map<String, Object>messageContent为空时
MQTT消息监听接口(IMqttListener):

定义监听消息接口。

public interface IMqttListener {

    String getTopic();

    void onMessage(Message message);
}

提供两个方法:
getTopic():监听者的topic,具备路由功能。
void onMessage(Message message):MQTT消息处理接口
监听消息Message:

public interface Message {

    //设备id
    String getDeviceId();

    //设备归属产品类
    String getProductId();

    long getTimestamp();

    String getSn();

    Map<String, Object> getData();

    Map<String, Object> getHeaders();

    Message addHeader(String var1, Object var2);

    Message addHeaderIfAbsent(String var1, Object var2);

    Message removeHeader(String var1);

    //消息体
    String getMessageContent();

}
其它:

InitMqttClientInfo MQTT客户端在启动前需要初始化内容:

public interface InitMqttClientInfo {

    void initInfo();

}

MQTT客户端SpringBoot Start

在Spring Boot应用程序中集成MQTT客户端是一个常见的需求,特别是当你需要处理IoT(物联网)设备的数据交换时。Spring Boot并没有直接提供MQTT客户端的starter,但你可以很容易地通过添加MQTT客户端库(到你的Spring Boot项目中来实现这一功能。

@Slf4j
@Configuration
@ConditionalOnProperty(value = "mqtt.sdk.enable", havingValue = "true")
public class MqttClientAutoConfiguration {
}

创建并注入MQTT客户端配置

结合Spring Boot 注解@ConfigurationProperties 实现MQTT配置信息注入

   @Bean
    @ConfigurationProperties(prefix = "mqtt.sdk")
    public MqttConfig mqttConfig() {
        return new MqttConfig();
    }

创建并注入一个默认消息监听器

 @Bean
    @ConditionalOnMissingBean
    public IMqttListener mqttListener() {
        return new IMqttListener() {
            @Override
            public String getTopic() {
                return "#";
            }

            @Override
            public void onMessage(Message message) {
                LoggerFactory.getLogger(IMqttListener.class)
                        .info("[默认消息监听器]接收到消息. Message[{}]", JSON.toJSONString(message));
            }
        };
    }

创建并注入MQTT客户端

现在,你可以在Spring Boot应用的任何地方注入MqttClient Bean,并使用它来订阅主题、发布消息等。

  @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean({MqttConfig.class, IMqttListener.class})
    public IMqttClient mqttClient(MqttConfig emqXConfig, List<IMqttListener> IMqttListenerList, Environment environment) {
        String serviceName = environment.getProperty("spring.application.name");
        String env = environment.getProperty("spring.profiles.active");
        IMqttClient mqttClient = new MqttClientApp(emqXConfig, IMqttListenerList,serviceName+"-"+env);
        Executors.newSingleThreadExecutor().execute(() -> mqttClient.connect().sync());
        Runtime.getRuntime().addShutdownHook(new Thread(mqttClient::mqttStop));
        return mqttClient;
    }

创建并注入MQTT对外推送消息类

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean({MqttConfig.class, IMqttClient.class})
    public IMqttApi mqttApi(IMqttClient IMqttClient) {
        return new MqttApiImpl(IMqttClient);
    }

Spring Boot SPI机制来集成MQTT自动配置

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

com.gitee.xmhzzz.component.mqtt.client.MqttClientAutoConfiguration

(Spring Boot 3.0 以上版本)

其它

关注公众号【 java程序猿技术】获取EMQX实践系列文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后端马农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值