MQTT
(消息队列遥测传输)是ISO标准(ISO/IEC PRF 20922
)下基于发布/订阅范式的消息协议。它工作在 TCP/IP
协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议。国内很多企业都广泛使用MQTT
作为Android
手机客户端与服务器端推送消息的协议。
springboot集成mqtt简单demo测试,后续还需深入理解应用。
依赖
<!--增加mqtt依赖,注意版本冲突问题-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
<!--<version>2.3.0.RELEASE</version>-->
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-stream</artifactId>
<!--<version>5.2.1.RELEASE</version>-->
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
<!--<version>5.2.1.RELEASE</version>-->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
properties配置
spring.mqtt.username=admin
spring.mqtt.password=public
#EMQX服务的tcp协议端口默认为1883
spring.mqtt.url=tcp://127.0.0.1:1883
spring.mqtt.default.topic=topic1
spring.mqtt.client.id=clientId-001
spring.mqtt.consumer.clientId=consumerClientId-001
spring.mqtt.consumer.defaultTopic=topic1
部分代码如下:
@Configuration
@IntegrationComponentScan
public class MqttConfig {
private static final Logger logger = LoggerFactory.getLogger(MqttConfig.class);
@Value("${spring.mqtt.username}")
private String username;
@Value("${spring.mqtt.password}")
private String password;
@Value("${spring.mqtt.url}")
private String hostUrl;
@Value("${spring.mqtt.client.id}")
private String clientId;
@Value("${spring.mqtt.default.topic}")
private String defaultTopic;
@Value("${spring.mqtt.consumer.clientId}")
private String consumerClientId;
@Value("${spring.mqtt.consumer.defaultTopic}")
private String consumerDefaultTopic;
//入站通道名(消费者)订阅的bean名称
public static final String CHANNEL_NAME_IN = "mqttInboundChannel";
//出站通道名(生产者)发布的bean名称
public static final String CHANNEL_NAME_OUT = "mqttOutboundChannel";
/**
* MQTT连接器选项
*
* @return {@link org.eclipse.paho.client.mqttv3.MqttConnectOptions}
*/
@Bean
public MqttConnectOptions getMqttConnectOptions() {
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setUserName(username);
mqttConnectOptions.setPassword(password.toCharArray());
mqttConnectOptions.setServerURIs(new String[]{hostUrl});
mqttConnectOptions.setKeepAliveInterval(2);
return mqttConnectOptions;
}
/**
* MQTT客户端
*
* @return {@link org.springframework.integration.mqtt.core.MqttPahoClientFactory}
*/
@Bean
public MqttPahoClientFactory mqttClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
factory.setConnectionOptions(getMqttConnectOptions());
return factory;
}
/*******************************生产者*******************************************/
/**
* MQTT信息通道(生产者)
*
* @return {@link org.springframework.messaging.MessageChannel}
*/
@Bean(name = CHANNEL_NAME_OUT)
public MessageChannel mqttOutboundChannel() {
return new DirectChannel();
}
/**
* MQTT消息处理器(生产者)
*
* @return
*/
@Bean
@ServiceActivator(inputChannel = CHANNEL_NAME_OUT)
public MessageHandler mqttOutbound() {
MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(clientId, mqttClientFactory());
messageHandler.setAsync(true);
messageHandler.setDefaultTopic(defaultTopic);
return messageHandler;
}
/*******************************消费者*******************************************/
/**
* MQTT信息通道(消费者)
*
* @return {@link org.springframework.messaging.MessageChannel}
*/
@Bean(name = CHANNEL_NAME_IN)
public MessageChannel mqttInboundChannel() {
return new DirectChannel();
}
/**
* MQTT消息订阅绑定(消费者)
*
* @return {@link org.springframework.integration.core.MessageProducer}
*/
@Bean
public MessageProducer inbound() {
// 可以同时消费(订阅)多个Topic
MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(consumerClientId, mqttClientFactory(), consumerDefaultTopic);
adapter.setCompletionTimeout(5000);
adapter.setConverter(new DefaultPahoMessageConverter());
adapter.setQos(1);
// 设置订阅通道
adapter.setOutputChannel(mqttInboundChannel());
return adapter;
}
/**
* MQTT消息处理器(消费者)
*
* @return {@link org.springframework.messaging.MessageHandler}
*/
@Bean
@ServiceActivator(inputChannel = CHANNEL_NAME_IN)
public MessageHandler handler() {
return new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString();
String msg = message.getPayload().toString();
logger.info("接收到订阅消息:\ntopic:" + topic + "\nmessage:" + msg);
}
};
//or 调用MqttMessageConsumer类处理收到的消息
//return new MqttMessageConsumer();
}
}
@MessagingGateway(defaultRequestChannel = "mqttOutboundChannel")
@Component
public interface MqttMessageProducer {
/**
* payload或者data是发送消息的内容
* topic是消息发送的主题,这里可以自己灵活定义,也可以使用默认的主题,就是配置文件的主题,qos是mqtt 对消息处理的几种机制分为0,1,2 其中0表示的是订阅者没收到消息不会再次发送,消息会丢失,1表示的是会尝试重试,一直到接收到消息,但这种情况可能导致订阅者收到多次重复消息,2相比多了一次去重的动作,确保订阅者收到的消息有一次
* 当然,这三种模式下的性能肯定也不一样,qos=0是最好的,2是最差的
*/
void sendToMqtt(String data);
void sendToMqtt(String payload, @Header(MqttHeaders.TOPIC) String topic);
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload);
}
@Component
public class MqttMessageConsumer implements MessageHandler {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void handleMessage(Message<?> message) throws MessagingException {
String topic = String.valueOf(message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC));
String payload = String.valueOf(message.getPayload());
logger.info("接收到 mqtt消息,主题:{} 消息:{}", topic, payload);
}
}
结果:
接收到订阅消息:
topic:topic1
message:111
EMQX服务监控信息如上。