spring项目使用EMQX,使用@Autowired注入失败报错空指针问题记录

本文详细描述了Java客户端使用MQTT订阅消息的过程,涉及MQTTConnect和MQTTListener部分代码。重点分析了在回调中使用@Autowired注入Service时遇到的空指针问题,提出了解决方案:在需要时动态使用ApplicationContext加载Bean。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java客户端使用MQTT订阅消息大致流程

  1. 首先通过消息服务器节点的地址,new 一个MqttClient连接对象然后给MqttClient设置回调。
  2. 这里是通过new 一个MqttCallback对象(注入失败问题就在这) 来实现对topic中消息的监听和处理,所以服务端的处理心跳消息的主要业务逻辑均在MqttCallback实例中的messageArrived方法中。
  3. 建立连接。
  4. 订阅topic。

MQTTConnect部分代码

    /**
     * 客户端connect连接mqtt服务器
     *
     * @param mqttCallback 回调函数
     **/
   public void setMqttClient(MqttCallback mqttCallback) throws MqttException {
        MqttConnectOptions options = mqttConnectOptions(USER_NAME, PASS_WORD);
        mqttClient.setCallback(mqttCallback);
        mqttClient.connect(options);
    }

    /**
     * MQTT连接参数设置
     */
    private MqttConnectOptions mqttConnectOptions(String userName, String passWord) throws MqttException {
        mqttClient = new MqttClient(HOST, clientId, new MemoryPersistence());
        MqttConnectOptions options = new MqttConnectOptions();
        options.setUserName(userName);
        options.setPassword(passWord.toCharArray());
        options.setConnectionTimeout(10);///默认:30
        options.setAutomaticReconnect(true);//默认:false
        options.setCleanSession(false);//默认:true
        //options.setKeepAliveInterval(20);//默认:60
        return options;
    }

MQTTListener部分代码

/**
* 这里采用了自定义一个ApplicationListener监听类,
* 在onApplicationEvent()方法中执行连接mqtt服务和订阅主题。
**/
@Slf4j
@Component
public class MQTTListener implements ApplicationListener<ContextRefreshedEvent> {

    private final MQTTConnect server;

    @Autowired
    public MQTTListener(MQTTConnect server) {
        this.server = server;
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        try {
            // 连接mqtt服务
            server.setMqttClient(new Callback(server));
            // 订阅主题
            server.sub("com/iot/init");
            server.sub("com/iot/init1");
            server.sub("com/iot/init2");
            server.sub("com/iot/init3");
        } catch (MqttException e) {
            log.error(e.getMessage(), e);
        }
    }
}

问题分析

由于我们需要在消息监听回调中执行业务逻辑,比如根据消息中的某个字段使用mapper查询数据库。所以在Callback类中用@Autowired引入的项目中的serviceImpl。这里可以看到注入的serviceImpl出现了空指针。

在这里插入图片描述

问题原因

在这里插入图片描述
在MQTTListener中我们使用了new来创建CallBack这个bean,那么我们在CallBack这个类的示例中注入bean就会失败,出现null。
这里原因可能是new出来的实例对象不由spring管理,所以其内部注入的bean也就失败了。(这里如果说的不对,希望大佬不吝赐教)

解决方法

解决方法就是使用到服务的时候,动态去加载Bean。
  1. 使用applicationContext的getBean()方法在使用的地方动态注入,比如以下的方式。
dynamicRoutingDataSource = applicationContext.getBean(DynamicRoutingDataSource.class);
  1. 在MQTTListener设置回调CallBack类时,使用注入的CallBack类的Bean。

在这里插入图片描述

总结

在Spring项目中,尽量统一把bean交给Spring容器管理,少使用new创建实例对象。

参考

记一次Spring项目中使用@Autowired注入bean,使用时报空指针异常的问题
Spring @Autowired注入为null,空指针异常

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值