一.注解定义
package 包名
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MqttListener {
String topic();
int qos() default 0;
}
这里注解定义了订阅的主题topic,和qos级别;
qos有三个级别:
0 最多一次
MQTT 中最简单的交付等级。在 QoS 0 下,消息发布后,对消息的投递没有任何确认或重传机制。这意味着消息可能会有丢失或传输失败的风险。适用于不需要可靠性且网络开销小的。
1 最少一次
消息发布后,至少会被传递一次,但可能存在重复传递的情况。
2 仅一次
消息发布后,只会被传递一次,不会发生重复传递的情况。名字虽然是仅一次,但是却是网络开销最大的。
topic:
1.普通订阅
格式为topic/subtopic格式,其中有#和+两个通配符,'+': 表示通配一个层级,例如 a/+,匹配 a/x, a/y。'#': 表示通配多个层级。例如 a/#,匹配 a/x, a/b/c/d
2.共享订阅
以 $share/<group-name>
为前缀的共享订阅是带群组的共享订阅:
group-name 可以为任意字符串,属于同一个群组内部的订阅者将以负载均衡接收消息,但 EMQX 会向不同群组广播消息。
例如,假设订阅者 s1,s2,s3 属于群组 g1,订阅者 s4,s5 属于群组 g2。那么当 EMQX 向这个主题发布消息 msg1 的时候:
-
EMQX 会向两个群组 g1 和 g2 同时发送 msg1
-
s1,s2,s3 中只有一个会收到 msg1
-
s4,s5 中只有一个会收到 msg1
示例 | 前缀 | 真实主题名 |
---|---|---|
$share/abc/t/1 | $share/abc/ | t/1 |
其他的一些mqtt高级特性例如遗嘱消息,保留消息,主题重写可以参考文档
二.创建连接
1.引入依赖
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
</dependency>
2.增加配置
mqtt: broker: ${MQTT_BROKER:地址} userName: ${MQTT_USERNAME:用户名} password: ${MQTT_PASSWORD:密码} caDir: ${MQTT_CA_DIR:ca证书}
3.创建连接
import com.nis.mqtt.utils.SSLUtils;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MqttConfig {
@Value("${mqtt.broker}")
private String broker;
@Value("${mqtt.userName:}")
private String userName;
@Value("${mqtt.password:}")
private String password;
@Value("${mqtt.caDir}")
private String caDir;
@Bean
public MqttClient init()
{
String clientId = MqttClient.generateClientId();
// 持久化
MemoryPersistence persistence = new MemoryPersistence();
// MQTT 连接选项
MqttConnectOptions connOpts = new MqttConnectOptions();
// 设置认证信息
connOpts.setUserName(userName);
connOpts.setPassword(password.toCharArray());
// 设置CA证书
// 证书文件可以通过其他管理
MqttClient client = null;
try {
connOpts.setSocketFactory(SSLUtils.getSingleSocketFactory(caDir));
client = new MqttClient(broker, clientId, persistence);
client.connect(connOpts);
} catch (Exception e) {
throw new RuntimeException(e);
}
return client;
}
}
三.扫描自动订阅
import com.nis.mqtt.aspect.annotion.MqttListener;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Method;
@Configuration
public class MqttBeanProcessor implements BeanPostProcessor {
@Autowired
private MqttClient mqttClient;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<?> beanClass = bean.getClass();
for (Method method : beanClass.getDeclaredMethods()) {
if (method.isAnnotationPresent(MqttListener.class)) {
MqttListener mqttListener = method.getAnnotation(MqttListener.class);
String topic = mqttListener.topic();
try {
mqttClient.subscribe(topic, mqttListener.qos(), (topic1, message) -> {
try {
method.invoke(bean, topic1, message);
} catch (Exception e) {
e.printStackTrace();
}
});
} catch (MqttException e) {
throw new RuntimeException(e);
}
}
}
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
}
四.如何使用
@MqttListener(topic = "$share/g1/test/spring")
public void onMessage(String topic, MqttMessage message) {
// 实现逻辑
}
五.写在最后
如果只是学习开发,可以使用EMQX:用于物联网、车联网和工业物联网的企业级 MQTT 平台,服务器有免费额度可用。当然也有开源社区版自己部署。GitHub - emqx/emqx: The most scalable open-source MQTT broker for IoT, IIoT, and connected vehicles