springboot + MQTTv3

springboot + MQTTv3

​ 最近项目使用到 MQTT,在引入 mica-mqtt 尝试并发发送消息出现消息丢失的情况,QoS =0,1,2 存在消息丢失情况,QoS=2最严重,所以只好切换到

org.eclipse.paho.client.mqttv3, 整合时候借鉴 mica-mqtt 开源部分思路;

引入相关依赖

 	<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-integration</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-mqtt</artifactId>
        </dependency>
        <dependency>
            <groupId>org.eclipse.paho</groupId>
            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
            <version>1.2.5</version>
        </dependency>
        <dependency>
            <groupId>org.dromara.dynamictp</groupId>
            <artifactId>dynamic-tp-core</artifactId>
        </dependency>
    </dependencies>

期待效果

// @Payload 可以byte[]、String、DevicePayload自定义类
@MqttSubscribe(value = "device/{deviceId}/{type}/report")
public void handleReportData(String topic
                                 @Variable(value = "deviceId") int deviceId,
                                 @Variable(value = "type") int type,
                                 @Payload DevicePayload payload) {
   
}

以下相关代码,全部贴出

MqttAutoConfiguration

import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dromara.dynamictp.common.em.QueueTypeEnum;
import org.dromara.dynamictp.core.executor.DtpExecutor;
import org.dromara.dynamictp.core.support.ThreadPoolBuilder;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.ExecutorChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;

import javax.net.ssl.SSLSocketFactory;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.TimeZone;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 参考官方: https://docs.spring.io/spring-integration/reference/mqtt.html
 */
@Slf4j
@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(MqttProperties.class)
public class MqttAutoConfiguration {
   

    // 默认MQTT线程名称
    public static final String DEFAULT_THREAD_POOL_NAME = "mqttThreadPoolExecutor";
    public static final String DEFAULT_OBJECT_MAPPER = "mqttObjectMapper";

    public static final String DEFAULT_TOPIC = "default/topic";
    public static final String MQTT_INBOUND_CHANNEL = "mqttInboundChannel";
    public static final String MQTT_OUTBOUND_CHANNEL = "mqttOutboundChannel";

    private final MqttProperties properties;

   
    @Bean
    public DefaultPahoMessageConverter defaultPahoMessageConverter(ObjectMapper objectMapper) {
   
        DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter();
        // 消息采用bytes
        converter.setPayloadAsBytes(true);
        converter.setBytesMessageMapper(new JsonMessageMapper(objectMapper));
        return converter;
    }

    @Bean
    public MethodArgumentResolverComposite methodArgumentResolverComposite(@Qualifier(DEFAULT_OBJECT_MAPPER) ObjectMapper objectMapper) {
   
        MethodArgumentResolverComposite resolverComposite = new MethodArgumentResolverComposite();
        resolverComposite.addResolver(new VariableMethodArgumentResolver())
                .addResolver(new PayloadMethodArgumentResolver(objectMapper))
                // 默认参数处理器,必须放在最后
                .addResolver(new DefaultMethodArgumentResolver());
        return resolverComposite;
    }

    @Bean
    public MqttPahoMessageDrivenChannelAdapter channelAdapter(DefaultPahoMessageConverter converter) {
   
        MqttClientProperties clientProperties = clientPropertiesIsPresent(properties.getConsumer()) ?
                properties.getConsumer() : properties;
        Objects.requireNonNull(clientProperties, "Mqtt client missing consumer configuration");

        String clientId = StringUtils.isNotEmpty(clientProperties.getClientId()) ?
                clientProperties.getClientId() : getClientId();

        MqttPahoMessageDrivenChannelAdapter adapter = new CustomMqttPahoMessageDrivenChannelAdapter(
                clientId, mqttClientFactory(clientProperties), DEFAULT_TOPIC);
        adapter.setCompletionTimeout(5000);
        adapter.setQos(0);
        adapter.setConverter(converter);
        // 移除默认
        adapter.removeTopic(DEFAULT_TOPIC);
        return adapter;
    }

    @Bean
    public MqttClientSubscribeManager mqttClientSubscribeManager(MqttPahoMessageDrivenChannelAdapter channelAdapter) {
   
        return new MqttClientSubscribeManager(channelAdapter);
    }

    // ========================= 消费者配置 ==========================

    /**
     * 消费者配置
     */
    @Bean(name = DEFAULT_THREAD_POOL_NAME)
    @ConditionalOnMissingBean(name = DEFAULT_THREAD_POOL_NAME)
    public DtpExecutor mqttThreadPoolExecutor() {
   
        int maximumPoolSize = 128;
        return ThreadPoolBuilder.newBuilder()
                .threadPoolName(DEFAULT_THREAD_POOL_NAME)
                .threadFactory("mq-consume")
                .corePoolSize(8)
                .maximumPoolSize(maximumPoolSize)
                .keepAliveTime(60)
                .allowCoreThreadTimeOut(Boolean.FALSE)
                .workQueue(QueueTypeEnum.SYNCHRONOUS_QUEUE.getName(), maximumPoolSize, Boolean.FALSE)
                .rejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy())
                .buildDynamic();
    }

    /**
     * 通道 
     */
    @Bean(name = MQTT_INBOUND_CHANNEL)
    public MessageChannel inboundMessageChannel(@Qualifier(DEFAULT_THREAD_POOL_NAME) DtpExecutor executor) {
   
        return new ExecutorChannel(executor);
    }

    /**
     * 入站适配器
     *
     * @see org.springframework.integration.dsl.context.IntegrationFlowBeanPostProcessor
     */
    @Bean
    public IntegrationFlow inboundIntegrationFlow(
要在Spring Boot中集成MQTTv3,你可以按照以下步骤进行操作: 1. 首先,在你的项目中引入MQTT依赖。你可以在pom.xml文件中添加以下代码来引入spring-integration-mqtt依赖: ```xml <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-mqtt</artifactId> </dependency> ``` 这将允许你在Spring Boot中使用MQTT相关的功能。 2. 其次,你需要安装和配置RabbitMQ作为你的MQTT代理服务器。你可以按照Docker安装RabbitMQ的教程进行安装,该教程可以在提供的链接中找到。 3. 安装完成后,你需要启用MQTT插件。在终端中输入以下命令来启用rabbitmq_mqtt插件: ``` rabbitmq-plugins enable rabbitmq_mqtt ``` 同样,你还需要启用rabbitmq_web_mqtt插件: ``` rabbitmq-plugins enable rabbitmq_web_mqtt ``` 这些命令将允许你在RabbitMQ上使用MQTTMQTT over WebSockets的功能。 4. 最后,你可以按照Spring Boot的官方文档或示例代码来配置和使用MQTT功能。你可以使用Spring Integration提供的MQTT适配器来与MQTT代理进行通信,并处理MQTT消息。 希望以上步骤对你有所帮助,如果你需要更详细的信息,请参考相关文档。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [springboot集成mqtt(超级无敌详细)](https://blog.csdn.net/qq_42862247/article/details/125536672)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [springboot集成mqtt](https://blog.csdn.net/qq_44413835/article/details/124249715)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值