Commit fe4a774c1e94ab3fe48a1672de44531e6cadf566

Authored by YunaiV
1 parent 5f2abdab

!253 iot,MessageBus增加iotRabbitMQMessageBus:https://gitee.com/zhijiantianya/yudao-cloud/pulls/253

yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusAutoConfiguration.java
... ... @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessag
7 7 import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener;
8 8 import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
9 9 import cn.iocoder.yudao.module.iot.core.messagebus.core.local.IotLocalMessageBus;
  10 +import cn.iocoder.yudao.module.iot.core.messagebus.core.rabbitmq.IotRabbitMQMessageBus;
10 11 import cn.iocoder.yudao.module.iot.core.messagebus.core.redis.IotRedisMessageBus;
11 12 import cn.iocoder.yudao.module.iot.core.messagebus.core.rocketmq.IotRocketMQMessageBus;
12 13 import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
... ... @@ -14,8 +15,11 @@ import lombok.extern.slf4j.Slf4j;
14 15 import org.apache.rocketmq.spring.autoconfigure.RocketMQProperties;
15 16 import org.apache.rocketmq.spring.core.RocketMQTemplate;
16 17 import org.redisson.api.RedissonClient;
  18 +import org.springframework.amqp.rabbit.core.RabbitAdmin;
  19 +import org.springframework.amqp.rabbit.core.RabbitTemplate;
17 20 import org.springframework.boot.autoconfigure.AutoConfiguration;
18 21 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  22 +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
19 23 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
20 24 import org.springframework.boot.context.properties.EnableConfigurationProperties;
21 25 import org.springframework.context.ApplicationContext;
... ... @@ -126,4 +130,25 @@ public class IotMessageBusAutoConfiguration {
126 130  
127 131 }
128 132  
129   -}
130 133 \ No newline at end of file
  134 + // ==================== RabbitMQ 实现 ====================
  135 +
  136 + @Configuration
  137 + @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "rabbitmq")
  138 + @ConditionalOnClass(RabbitTemplate.class)
  139 + public static class IotRabbitMQMessageBusConfiguration {
  140 +
  141 + @Bean
  142 + @ConditionalOnMissingBean
  143 + public RabbitAdmin rabbitAdmin(RabbitTemplate rabbitTemplate) {
  144 + return new RabbitAdmin(rabbitTemplate);
  145 + }
  146 +
  147 + @Bean
  148 + public IotRabbitMQMessageBus iotRabbitMQMessageBus(RabbitTemplate rabbitTemplate, RabbitAdmin rabbitAdmin) {
  149 + log.info("[iotRabbitMQMessageBus][创建 IoT RabbitMQ 消息总线]");
  150 + return new IotRabbitMQMessageBus(rabbitTemplate, rabbitAdmin);
  151 + }
  152 +
  153 + }
  154 +
  155 +}
... ...
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rabbitmq/IotRabbitMQMessageBus.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.core.messagebus.core.rabbitmq;
  2 +
  3 +import cn.hutool.core.util.TypeUtil;
  4 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  5 +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
  6 +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber;
  7 +import jakarta.annotation.PreDestroy;
  8 +import lombok.Getter;
  9 +import lombok.RequiredArgsConstructor;
  10 +import lombok.extern.slf4j.Slf4j;
  11 +import org.springframework.amqp.core.AcknowledgeMode;
  12 +import org.springframework.amqp.core.Binding;
  13 +import org.springframework.amqp.core.BindingBuilder;
  14 +import org.springframework.amqp.core.MessageBuilder;
  15 +import org.springframework.amqp.core.Queue;
  16 +import org.springframework.amqp.core.TopicExchange;
  17 +import org.springframework.amqp.rabbit.core.RabbitAdmin;
  18 +import org.springframework.amqp.rabbit.core.RabbitTemplate;
  19 +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
  20 +import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
  21 +
  22 +import java.lang.reflect.Type;
  23 +import java.util.ArrayList;
  24 +import java.util.List;
  25 +
  26 +/**
  27 + * 基于 RabbitMQ 的 {@link IotMessageBus} 实现类
  28 + *
  29 + * @author ywc
  30 + */
  31 +@RequiredArgsConstructor
  32 +@Slf4j
  33 +public class IotRabbitMQMessageBus implements IotMessageBus {
  34 +
  35 + private static final String ROUTING_KEY = "#";
  36 +
  37 + private final RabbitTemplate rabbitTemplate;
  38 +
  39 + private final RabbitAdmin rabbitAdmin;
  40 +
  41 + @Getter
  42 + private final List<IotMessageSubscriber<?>> subscribers = new ArrayList<>();
  43 +
  44 + private final List<SimpleMessageListenerContainer> containers = new ArrayList<>();
  45 +
  46 + @Override
  47 + public void post(String topic, Object message) {
  48 + rabbitTemplate.send(topic, ROUTING_KEY, MessageBuilder.withBody(JsonUtils.toJsonByte(message)).build());
  49 + log.info("[post][topic({}) 发送消息({})]", topic, message);
  50 + }
  51 +
  52 + @Override
  53 + @SuppressWarnings("DataFlowIssue")
  54 + public void register(IotMessageSubscriber<?> subscriber) {
  55 + Type type = TypeUtil.getTypeArgument(subscriber.getClass(), 0);
  56 + if (type == null) {
  57 + throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName()));
  58 + }
  59 +
  60 + // 1.1 声明交换机、队列和绑定关系
  61 + Queue queue = new Queue(subscriber.getGroup(), true, false, false);
  62 + rabbitAdmin.declareQueue(queue);
  63 + TopicExchange exchange = new TopicExchange(subscriber.getTopic());
  64 + rabbitAdmin.declareExchange(exchange);
  65 + Binding binding = BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY);
  66 + rabbitAdmin.declareBinding(binding);
  67 +
  68 + // 1.2 创建消费容器
  69 + SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(rabbitTemplate.getConnectionFactory());
  70 + container.setQueues(queue);
  71 + container.setConcurrentConsumers(1);
  72 + container.setMaxConcurrentConsumers(10);
  73 + container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
  74 + container.setMessageListener((ChannelAwareMessageListener) (message, channel) -> {
  75 + try {
  76 + subscriber.onMessage(JsonUtils.parseObject(message.getBody(), type));
  77 + channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
  78 + } catch (Exception ex) {
  79 + log.error("[onMessage][topic({}/{}) message({}) 消费者({}) 处理异常]",
  80 + subscriber.getTopic(), subscriber.getGroup(), message, subscriber.getClass().getName(), ex);
  81 + channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
  82 + }
  83 + });
  84 + container.start();
  85 +
  86 + // 2. 保存消费者引用
  87 + containers.add(container);
  88 + subscribers.add(subscriber);
  89 + }
  90 +
  91 + @PreDestroy
  92 + public void destroy() {
  93 + for (SimpleMessageListenerContainer container : containers) {
  94 + try {
  95 + container.stop();
  96 + container.destroy();
  97 + log.info("[destroy][关闭 RabbitMQ 消费者容器成功]");
  98 + } catch (Exception e) {
  99 + log.error("[destroy][关闭 RabbitMQ 消费者容器异常]", e);
  100 + }
  101 + }
  102 + }
  103 +
  104 +}
... ...