Commit 19cf311b7e476076333ab8981afd093445e5213c
1 parent
69e25eea
feat:【IoT 物联网】增加 redis + event-bus 的实现
Showing
13 changed files
with
160 additions
and
48 deletions
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQConsumerAutoConfiguration.java
| @@ -69,9 +69,8 @@ public class YudaoRedisMQConsumerAutoConfiguration { | @@ -69,9 +69,8 @@ public class YudaoRedisMQConsumerAutoConfiguration { | ||
| 69 | @ConditionalOnBean(AbstractRedisStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听 | 69 | @ConditionalOnBean(AbstractRedisStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听 |
| 70 | public RedisPendingMessageResendJob redisPendingMessageResendJob(List<AbstractRedisStreamMessageListener<?>> listeners, | 70 | public RedisPendingMessageResendJob redisPendingMessageResendJob(List<AbstractRedisStreamMessageListener<?>> listeners, |
| 71 | RedisMQTemplate redisTemplate, | 71 | RedisMQTemplate redisTemplate, |
| 72 | - @Value("${spring.application.name}") String groupName, | ||
| 73 | RedissonClient redissonClient) { | 72 | RedissonClient redissonClient) { |
| 74 | - return new RedisPendingMessageResendJob(listeners, redisTemplate, groupName, redissonClient); | 73 | + return new RedisPendingMessageResendJob(listeners, redisTemplate, redissonClient); |
| 75 | } | 74 | } |
| 76 | 75 | ||
| 77 | /** | 76 | /** |
| @@ -141,14 +140,14 @@ public class YudaoRedisMQConsumerAutoConfiguration { | @@ -141,14 +140,14 @@ public class YudaoRedisMQConsumerAutoConfiguration { | ||
| 141 | * | 140 | * |
| 142 | * @return 消费者名字 | 141 | * @return 消费者名字 |
| 143 | */ | 142 | */ |
| 144 | - private static String buildConsumerName() { | 143 | + public static String buildConsumerName() { |
| 145 | return String.format("%s@%d", SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID()); | 144 | return String.format("%s@%d", SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID()); |
| 146 | } | 145 | } |
| 147 | 146 | ||
| 148 | /** | 147 | /** |
| 149 | * 校验 Redis 版本号,是否满足最低的版本号要求! | 148 | * 校验 Redis 版本号,是否满足最低的版本号要求! |
| 150 | */ | 149 | */ |
| 151 | - private static void checkRedisVersion(RedisTemplate<String, ?> redisTemplate) { | 150 | + public static void checkRedisVersion(RedisTemplate<String, ?> redisTemplate) { |
| 152 | // 获得 Redis 版本 | 151 | // 获得 Redis 版本 |
| 153 | Properties info = redisTemplate.execute((RedisCallback<Properties>) RedisServerCommands::info); | 152 | Properties info = redisTemplate.execute((RedisCallback<Properties>) RedisServerCommands::info); |
| 154 | String version = MapUtil.getStr(info, "redis_version"); | 153 | String version = MapUtil.getStr(info, "redis_version"); |
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java
| @@ -35,7 +35,6 @@ public class RedisPendingMessageResendJob { | @@ -35,7 +35,6 @@ public class RedisPendingMessageResendJob { | ||
| 35 | 35 | ||
| 36 | private final List<AbstractRedisStreamMessageListener<?>> listeners; | 36 | private final List<AbstractRedisStreamMessageListener<?>> listeners; |
| 37 | private final RedisMQTemplate redisTemplate; | 37 | private final RedisMQTemplate redisTemplate; |
| 38 | - private final String groupName; | ||
| 39 | private final RedissonClient redissonClient; | 38 | private final RedissonClient redissonClient; |
| 40 | 39 | ||
| 41 | /** | 40 | /** |
| @@ -64,13 +63,13 @@ public class RedisPendingMessageResendJob { | @@ -64,13 +63,13 @@ public class RedisPendingMessageResendJob { | ||
| 64 | private void execute() { | 63 | private void execute() { |
| 65 | StreamOperations<String, Object, Object> ops = redisTemplate.getRedisTemplate().opsForStream(); | 64 | StreamOperations<String, Object, Object> ops = redisTemplate.getRedisTemplate().opsForStream(); |
| 66 | listeners.forEach(listener -> { | 65 | listeners.forEach(listener -> { |
| 67 | - PendingMessagesSummary pendingMessagesSummary = Objects.requireNonNull(ops.pending(listener.getStreamKey(), groupName)); | 66 | + PendingMessagesSummary pendingMessagesSummary = Objects.requireNonNull(ops.pending(listener.getStreamKey(), listener.getGroup())); |
| 68 | // 每个消费者的 pending 队列消息数量 | 67 | // 每个消费者的 pending 队列消息数量 |
| 69 | Map<String, Long> pendingMessagesPerConsumer = pendingMessagesSummary.getPendingMessagesPerConsumer(); | 68 | Map<String, Long> pendingMessagesPerConsumer = pendingMessagesSummary.getPendingMessagesPerConsumer(); |
| 70 | pendingMessagesPerConsumer.forEach((consumerName, pendingMessageCount) -> { | 69 | pendingMessagesPerConsumer.forEach((consumerName, pendingMessageCount) -> { |
| 71 | log.info("[processPendingMessage][消费者({}) 消息数量({})]", consumerName, pendingMessageCount); | 70 | log.info("[processPendingMessage][消费者({}) 消息数量({})]", consumerName, pendingMessageCount); |
| 72 | // 每个消费者的 pending消息的详情信息 | 71 | // 每个消费者的 pending消息的详情信息 |
| 73 | - PendingMessages pendingMessages = ops.pending(listener.getStreamKey(), Consumer.from(groupName, consumerName), Range.unbounded(), pendingMessageCount); | 72 | + PendingMessages pendingMessages = ops.pending(listener.getStreamKey(), Consumer.from(listener.getGroup(), consumerName), Range.unbounded(), pendingMessageCount); |
| 74 | if (pendingMessages.isEmpty()) { | 73 | if (pendingMessages.isEmpty()) { |
| 75 | return; | 74 | return; |
| 76 | } | 75 | } |
| @@ -91,7 +90,7 @@ public class RedisPendingMessageResendJob { | @@ -91,7 +90,7 @@ public class RedisPendingMessageResendJob { | ||
| 91 | .ofObject(records.get(0).getValue()) // 设置内容 | 90 | .ofObject(records.get(0).getValue()) // 设置内容 |
| 92 | .withStreamKey(listener.getStreamKey())); | 91 | .withStreamKey(listener.getStreamKey())); |
| 93 | // ack 消息消费完成 | 92 | // ack 消息消费完成 |
| 94 | - redisTemplate.getRedisTemplate().opsForStream().acknowledge(groupName, records.get(0)); | 93 | + redisTemplate.getRedisTemplate().opsForStream().acknowledge(listener.getGroup(), records.get(0)); |
| 95 | log.info("[processPendingMessage][消息({})重新投递成功]", records.get(0).getId()); | 94 | log.info("[processPendingMessage][消息({})重新投递成功]", records.get(0).getId()); |
| 96 | }); | 95 | }); |
| 97 | }); | 96 | }); |
yudao-module-iot/yudao-module-iot-core/pom.xml
| @@ -33,6 +33,11 @@ | @@ -33,6 +33,11 @@ | ||
| 33 | 33 | ||
| 34 | <!-- 消息中间件相关(可选依赖) --> | 34 | <!-- 消息中间件相关(可选依赖) --> |
| 35 | <dependency> | 35 | <dependency> |
| 36 | + <groupId>cn.iocoder.boot</groupId> | ||
| 37 | + <artifactId>yudao-spring-boot-starter-mq</artifactId> | ||
| 38 | + </dependency> | ||
| 39 | + | ||
| 40 | + <dependency> | ||
| 36 | <groupId>org.springframework.data</groupId> | 41 | <groupId>org.springframework.data</groupId> |
| 37 | <artifactId>spring-data-redis</artifactId> | 42 | <artifactId>spring-data-redis</artifactId> |
| 38 | <optional>true</optional> | 43 | <optional>true</optional> |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusAutoConfiguration.java
| 1 | package cn.iocoder.yudao.module.iot.core.messagebus.config; | 1 | package cn.iocoder.yudao.module.iot.core.messagebus.config; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; | 3 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; |
| 4 | -import cn.iocoder.yudao.module.iot.core.messagebus.core.local.LocalIotMessageBus; | ||
| 5 | -import cn.iocoder.yudao.module.iot.core.messagebus.core.rocketmq.RocketMQIotMessageBus; | 4 | +import cn.iocoder.yudao.module.iot.core.messagebus.core.local.IotLocalMessageBus; |
| 5 | +import cn.iocoder.yudao.module.iot.core.messagebus.core.redis.IotRedisMessageBus; | ||
| 6 | +import cn.iocoder.yudao.module.iot.core.messagebus.core.rocketmq.IotRocketMQMessageBus; | ||
| 6 | import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; | 7 | import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; |
| 7 | import lombok.extern.slf4j.Slf4j; | 8 | import lombok.extern.slf4j.Slf4j; |
| 8 | import org.apache.rocketmq.spring.autoconfigure.RocketMQProperties; | 9 | import org.apache.rocketmq.spring.autoconfigure.RocketMQProperties; |
| @@ -14,6 +15,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties | @@ -14,6 +15,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties | ||
| 14 | import org.springframework.context.ApplicationContext; | 15 | import org.springframework.context.ApplicationContext; |
| 15 | import org.springframework.context.annotation.Bean; | 16 | import org.springframework.context.annotation.Bean; |
| 16 | import org.springframework.context.annotation.Configuration; | 17 | import org.springframework.context.annotation.Configuration; |
| 18 | +import org.springframework.data.redis.core.RedisTemplate; | ||
| 19 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
| 17 | 20 | ||
| 18 | /** | 21 | /** |
| 19 | * IoT 消息总线自动配置 | 22 | * IoT 消息总线自动配置 |
| @@ -34,12 +37,12 @@ public class IotMessageBusAutoConfiguration { | @@ -34,12 +37,12 @@ public class IotMessageBusAutoConfiguration { | ||
| 34 | 37 | ||
| 35 | @Configuration | 38 | @Configuration |
| 36 | @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "local", matchIfMissing = true) | 39 | @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "local", matchIfMissing = true) |
| 37 | - public static class LocalIotMessageBusConfiguration { | 40 | + public static class IotLocalMessageBusConfiguration { |
| 38 | 41 | ||
| 39 | @Bean | 42 | @Bean |
| 40 | - public IotMessageBus localIotMessageBus(ApplicationContext applicationContext) { | ||
| 41 | - log.info("[localIotMessageBus][创建 Local IoT 消息总线]"); | ||
| 42 | - return new LocalIotMessageBus(applicationContext); | 43 | + public IotMessageBus iotLocalMessageBus(ApplicationContext applicationContext) { |
| 44 | + log.info("[iotLocalMessageBus][创建 IoT Local 消息总线]"); | ||
| 45 | + return new IotLocalMessageBus(applicationContext); | ||
| 43 | } | 46 | } |
| 44 | 47 | ||
| 45 | } | 48 | } |
| @@ -49,13 +52,28 @@ public class IotMessageBusAutoConfiguration { | @@ -49,13 +52,28 @@ public class IotMessageBusAutoConfiguration { | ||
| 49 | @Configuration | 52 | @Configuration |
| 50 | @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "rocketmq") | 53 | @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "rocketmq") |
| 51 | @ConditionalOnClass(RocketMQTemplate.class) | 54 | @ConditionalOnClass(RocketMQTemplate.class) |
| 52 | - public static class RocketMQIotMessageBusConfiguration { | 55 | + public static class IotRocketMQMessageBusConfiguration { |
| 53 | 56 | ||
| 54 | @Bean | 57 | @Bean |
| 55 | - @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") | ||
| 56 | - public IotMessageBus rocketMQIotMessageBus(RocketMQProperties rocketMQProperties, RocketMQTemplate rocketMQTemplate) { | ||
| 57 | - log.info("[rocketMQIotMessageBus][创建 RocketMQ IoT 消息总线]"); | ||
| 58 | - return new RocketMQIotMessageBus(rocketMQProperties, rocketMQTemplate); | 58 | + public IotMessageBus iotRocketMQMessageBus(RocketMQProperties rocketMQProperties, |
| 59 | + RocketMQTemplate rocketMQTemplate) { | ||
| 60 | + log.info("[iotRocketMQMessageBus][创建 IoT RocketMQ 消息总线]"); | ||
| 61 | + return new IotRocketMQMessageBus(rocketMQProperties, rocketMQTemplate); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + // ==================== Redis 实现 ==================== | ||
| 67 | + | ||
| 68 | + @Configuration | ||
| 69 | + @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "redis") | ||
| 70 | + @ConditionalOnClass(RedisTemplate.class) | ||
| 71 | + public static class IotRedisMessageBusConfiguration { | ||
| 72 | + | ||
| 73 | + @Bean | ||
| 74 | + public IotMessageBus iotRedisMessageBus(StringRedisTemplate redisTemplate) { | ||
| 75 | + log.info("[iotRedisMessageBus][创建 IoT Redis 消息总线]"); | ||
| 76 | + return new IotRedisMessageBus(redisTemplate); | ||
| 59 | } | 77 | } |
| 60 | 78 | ||
| 61 | } | 79 | } |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessage.java renamed to yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/IotLocalMessage.java
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBus.java renamed to yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/IotLocalMessageBus.java
| @@ -22,7 +22,7 @@ import java.util.Map; | @@ -22,7 +22,7 @@ import java.util.Map; | ||
| 22 | */ | 22 | */ |
| 23 | @RequiredArgsConstructor | 23 | @RequiredArgsConstructor |
| 24 | @Slf4j | 24 | @Slf4j |
| 25 | -public class LocalIotMessageBus implements IotMessageBus { | 25 | +public class IotLocalMessageBus implements IotMessageBus { |
| 26 | 26 | ||
| 27 | private final ApplicationContext applicationContext; | 27 | private final ApplicationContext applicationContext; |
| 28 | 28 | ||
| @@ -34,7 +34,7 @@ public class LocalIotMessageBus implements IotMessageBus { | @@ -34,7 +34,7 @@ public class LocalIotMessageBus implements IotMessageBus { | ||
| 34 | 34 | ||
| 35 | @Override | 35 | @Override |
| 36 | public void post(String topic, Object message) { | 36 | public void post(String topic, Object message) { |
| 37 | - applicationContext.publishEvent(new LocalIotMessage(topic, message)); | 37 | + applicationContext.publishEvent(new IotLocalMessage(topic, message)); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | @Override | 40 | @Override |
| @@ -48,7 +48,7 @@ public class LocalIotMessageBus implements IotMessageBus { | @@ -48,7 +48,7 @@ public class LocalIotMessageBus implements IotMessageBus { | ||
| 48 | 48 | ||
| 49 | @EventListener | 49 | @EventListener |
| 50 | @SuppressWarnings({"unchecked", "rawtypes"}) | 50 | @SuppressWarnings({"unchecked", "rawtypes"}) |
| 51 | - public void onMessage(LocalIotMessage message) { | 51 | + public void onMessage(IotLocalMessage message) { |
| 52 | String topic = message.getTopic(); | 52 | String topic = message.getTopic(); |
| 53 | List<IotMessageSubscriber<?>> topicSubscribers = subscribers.get(topic); | 53 | List<IotMessageSubscriber<?>> topicSubscribers = subscribers.get(topic); |
| 54 | if (CollUtil.isEmpty(topicSubscribers)) { | 54 | if (CollUtil.isEmpty(topicSubscribers)) { |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/redis/IotRedisMessageBus.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.core.messagebus.core.redis; | ||
| 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.PostConstruct; | ||
| 8 | +import jakarta.annotation.PreDestroy; | ||
| 9 | +import lombok.extern.slf4j.Slf4j; | ||
| 10 | +import org.springframework.data.redis.connection.stream.*; | ||
| 11 | +import org.springframework.data.redis.core.RedisTemplate; | ||
| 12 | +import org.springframework.data.redis.stream.StreamMessageListenerContainer; | ||
| 13 | + | ||
| 14 | +import java.lang.reflect.Type; | ||
| 15 | + | ||
| 16 | +import static cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQConsumerAutoConfiguration.buildConsumerName; | ||
| 17 | +import static cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQConsumerAutoConfiguration.checkRedisVersion; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * Redis 的 {@link IotMessageBus} 实现类 | ||
| 21 | + * | ||
| 22 | + * @author 芋道源码 | ||
| 23 | + */ | ||
| 24 | +@Slf4j | ||
| 25 | +public class IotRedisMessageBus implements IotMessageBus { | ||
| 26 | + | ||
| 27 | + private final RedisTemplate<String, ?> redisTemplate; | ||
| 28 | + | ||
| 29 | + private final StreamMessageListenerContainer<String, ObjectRecord<String, String>> redisStreamMessageListenerContainer; | ||
| 30 | + | ||
| 31 | + public IotRedisMessageBus(RedisTemplate<String, ?> redisTemplate) { | ||
| 32 | + this.redisTemplate = redisTemplate; | ||
| 33 | + checkRedisVersion(redisTemplate); | ||
| 34 | + // 创建 options 配置 | ||
| 35 | + StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, ObjectRecord<String, String>> containerOptions = | ||
| 36 | + StreamMessageListenerContainer.StreamMessageListenerContainerOptions.builder() | ||
| 37 | + .batchSize(10) // 一次性最多拉取多少条消息 | ||
| 38 | + .targetType(String.class) // 目标类型。统一使用 String,通过自己封装的 AbstractStreamMessageListener 去反序列化 | ||
| 39 | + .build(); | ||
| 40 | + // 创建 container 对象 | ||
| 41 | + this.redisStreamMessageListenerContainer = | ||
| 42 | + StreamMessageListenerContainer.create(redisTemplate.getRequiredConnectionFactory(), containerOptions); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + @PostConstruct | ||
| 46 | + public void init() { | ||
| 47 | + this.redisStreamMessageListenerContainer.start(); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + @PreDestroy | ||
| 51 | + public void destroy() { | ||
| 52 | + this.redisStreamMessageListenerContainer.stop(); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + @Override | ||
| 56 | + public void post(String topic, Object message) { | ||
| 57 | + redisTemplate.opsForStream().add(StreamRecords.newRecord() | ||
| 58 | + .ofObject(JsonUtils.toJsonString(message)) // 设置内容 | ||
| 59 | + .withStreamKey(topic)); // 设置 stream key | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + @Override | ||
| 63 | + public void register(IotMessageSubscriber<?> subscriber) { | ||
| 64 | + Type type = TypeUtil.getTypeArgument(subscriber.getClass(), 0); | ||
| 65 | + if (type == null) { | ||
| 66 | + throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName())); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + // 创建 listener 对应的消费者分组 | ||
| 70 | + try { | ||
| 71 | + redisTemplate.opsForStream().createGroup(subscriber.getTopic(), subscriber.getGroup()); | ||
| 72 | + } catch (Exception ignore) { | ||
| 73 | + } | ||
| 74 | + // 创建 Consumer 对象 | ||
| 75 | + String consumerName = buildConsumerName(); | ||
| 76 | + Consumer consumer = Consumer.from(subscriber.getGroup(), consumerName); | ||
| 77 | + // 设置 Consumer 消费进度,以最小消费进度为准 | ||
| 78 | + StreamOffset<String> streamOffset = StreamOffset.create(subscriber.getTopic(), ReadOffset.lastConsumed()); | ||
| 79 | + // 设置 Consumer 监听 | ||
| 80 | + StreamMessageListenerContainer.StreamReadRequestBuilder<String> builder = StreamMessageListenerContainer.StreamReadRequest | ||
| 81 | + .builder(streamOffset).consumer(consumer) | ||
| 82 | + .autoAcknowledge(false) // 不自动 ack | ||
| 83 | + .cancelOnError(throwable -> false); // 默认配置,发生异常就取消消费,显然不符合预期;因此,我们设置为 false | ||
| 84 | + redisStreamMessageListenerContainer.register(builder.build(), message -> { | ||
| 85 | + // 消费消息 | ||
| 86 | + subscriber.onMessage(JsonUtils.parseObject(message.getValue(), type)); | ||
| 87 | + // ack 消息消费完成 | ||
| 88 | + redisTemplate.opsForStream().acknowledge(subscriber.getGroup(), message); | ||
| 89 | + }); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | +} |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBus.java renamed to yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/IotRocketMQMessageBus.java
| @@ -4,6 +4,7 @@ import cn.hutool.core.util.TypeUtil; | @@ -4,6 +4,7 @@ import cn.hutool.core.util.TypeUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 4 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 5 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; | 5 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; |
| 6 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; | 6 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; |
| 7 | +import jakarta.annotation.PreDestroy; | ||
| 7 | import lombok.RequiredArgsConstructor; | 8 | import lombok.RequiredArgsConstructor; |
| 8 | import lombok.SneakyThrows; | 9 | import lombok.SneakyThrows; |
| 9 | import lombok.extern.slf4j.Slf4j; | 10 | import lombok.extern.slf4j.Slf4j; |
| @@ -15,8 +16,6 @@ import org.apache.rocketmq.common.message.MessageExt; | @@ -15,8 +16,6 @@ import org.apache.rocketmq.common.message.MessageExt; | ||
| 15 | import org.apache.rocketmq.spring.autoconfigure.RocketMQProperties; | 16 | import org.apache.rocketmq.spring.autoconfigure.RocketMQProperties; |
| 16 | import org.apache.rocketmq.spring.core.RocketMQTemplate; | 17 | import org.apache.rocketmq.spring.core.RocketMQTemplate; |
| 17 | 18 | ||
| 18 | -import jakarta.annotation.PreDestroy; | ||
| 19 | - | ||
| 20 | import java.lang.reflect.Type; | 19 | import java.lang.reflect.Type; |
| 21 | import java.util.ArrayList; | 20 | import java.util.ArrayList; |
| 22 | import java.util.List; | 21 | import java.util.List; |
| @@ -28,7 +27,7 @@ import java.util.List; | @@ -28,7 +27,7 @@ import java.util.List; | ||
| 28 | */ | 27 | */ |
| 29 | @RequiredArgsConstructor | 28 | @RequiredArgsConstructor |
| 30 | @Slf4j | 29 | @Slf4j |
| 31 | -public class RocketMQIotMessageBus implements IotMessageBus { | 30 | +public class IotRocketMQMessageBus implements IotMessageBus { |
| 32 | 31 | ||
| 33 | private final RocketMQProperties rocketMQProperties; | 32 | private final RocketMQProperties rocketMQProperties; |
| 34 | 33 | ||
| @@ -39,6 +38,21 @@ public class RocketMQIotMessageBus implements IotMessageBus { | @@ -39,6 +38,21 @@ public class RocketMQIotMessageBus implements IotMessageBus { | ||
| 39 | */ | 38 | */ |
| 40 | private final List<DefaultMQPushConsumer> topicConsumers = new ArrayList<>(); | 39 | private final List<DefaultMQPushConsumer> topicConsumers = new ArrayList<>(); |
| 41 | 40 | ||
| 41 | + /** | ||
| 42 | + * 销毁时关闭所有消费者 | ||
| 43 | + */ | ||
| 44 | + @PreDestroy | ||
| 45 | + public void destroy() { | ||
| 46 | + for (DefaultMQPushConsumer consumer : topicConsumers) { | ||
| 47 | + try { | ||
| 48 | + consumer.shutdown(); | ||
| 49 | + log.info("[destroy][关闭 group({}) 的消费者成功]", consumer.getConsumerGroup()); | ||
| 50 | + } catch (Exception e) { | ||
| 51 | + log.error("[destroy]关闭 group({}) 的消费者异常]", consumer.getConsumerGroup(), e); | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + } | ||
| 55 | + | ||
| 42 | @Override | 56 | @Override |
| 43 | public void post(String topic, Object message) { | 57 | public void post(String topic, Object message) { |
| 44 | // TODO @芋艿:需要 orderly! | 58 | // TODO @芋艿:需要 orderly! |
| @@ -81,19 +95,4 @@ public class RocketMQIotMessageBus implements IotMessageBus { | @@ -81,19 +95,4 @@ public class RocketMQIotMessageBus implements IotMessageBus { | ||
| 81 | topicConsumers.add(consumer); | 95 | topicConsumers.add(consumer); |
| 82 | } | 96 | } |
| 83 | 97 | ||
| 84 | - /** | ||
| 85 | - * 销毁时关闭所有消费者 | ||
| 86 | - */ | ||
| 87 | - @PreDestroy | ||
| 88 | - public void destroy() { | ||
| 89 | - for (DefaultMQPushConsumer consumer : topicConsumers) { | ||
| 90 | - try { | ||
| 91 | - consumer.shutdown(); | ||
| 92 | - log.info("[destroy][关闭 group({}) 的消费者成功]", consumer.getConsumerGroup()); | ||
| 93 | - } catch (Exception e) { | ||
| 94 | - log.error("[destroy]关闭 group({}) 的消费者异常]", consumer.getConsumerGroup(), e); | ||
| 95 | - } | ||
| 96 | - } | ||
| 97 | - } | ||
| 98 | - | ||
| 99 | } | 98 | } |
| 100 | \ No newline at end of file | 99 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBusIntegrationTest.java
| @@ -17,7 +17,7 @@ import java.util.concurrent.atomic.AtomicInteger; | @@ -17,7 +17,7 @@ import java.util.concurrent.atomic.AtomicInteger; | ||
| 17 | import static org.junit.jupiter.api.Assertions.*; | 17 | import static org.junit.jupiter.api.Assertions.*; |
| 18 | 18 | ||
| 19 | /** | 19 | /** |
| 20 | - * {@link LocalIotMessageBus} 集成测试 | 20 | + * {@link IotLocalMessageBus} 集成测试 |
| 21 | * | 21 | * |
| 22 | * @author 芋道源码 | 22 | * @author 芋道源码 |
| 23 | */ | 23 | */ |
yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBusTest.java
| @@ -21,7 +21,7 @@ import java.util.concurrent.atomic.AtomicReference; | @@ -21,7 +21,7 @@ import java.util.concurrent.atomic.AtomicReference; | ||
| 21 | import static org.junit.jupiter.api.Assertions.*; | 21 | import static org.junit.jupiter.api.Assertions.*; |
| 22 | 22 | ||
| 23 | /** | 23 | /** |
| 24 | - * {@link RocketMQIotMessageBus} 集成测试 | 24 | + * {@link IotRocketMQMessageBus} 集成测试 |
| 25 | * | 25 | * |
| 26 | * @author 芋道源码 | 26 | * @author 芋道源码 |
| 27 | */ | 27 | */ |
yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application-local.yaml
| @@ -31,7 +31,7 @@ yudao: | @@ -31,7 +31,7 @@ yudao: | ||
| 31 | # 针对引入的 EMQX 组件的配置 | 31 | # 针对引入的 EMQX 组件的配置 |
| 32 | # ==================================== | 32 | # ==================================== |
| 33 | emqx: | 33 | emqx: |
| 34 | - enabled: true | 34 | + enabled: false |
| 35 | http-port: 8090 # MQTT HTTP 服务端口 | 35 | http-port: 8090 # MQTT HTTP 服务端口 |
| 36 | mqtt-host: 127.0.0.1 # MQTT Broker 地址 | 36 | mqtt-host: 127.0.0.1 # MQTT Broker 地址 |
| 37 | mqtt-port: 1883 # MQTT Broker 端口 | 37 | mqtt-port: 1883 # MQTT Broker 端口 |
| @@ -44,7 +44,7 @@ yudao: | @@ -44,7 +44,7 @@ yudao: | ||
| 44 | 44 | ||
| 45 | # 消息总线配置 | 45 | # 消息总线配置 |
| 46 | message-bus: | 46 | message-bus: |
| 47 | - type: rocketmq # 本地开发使用 RocketMQ | 47 | + type: redis # 本地开发使用 RocketMQ |
| 48 | 48 | ||
| 49 | --- #################### 日志相关配置 #################### | 49 | --- #################### 日志相关配置 #################### |
| 50 | 50 |
yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml
| @@ -37,14 +37,14 @@ yudao: | @@ -37,14 +37,14 @@ yudao: | ||
| 37 | # 针对引入的 EMQX 组件的配置 | 37 | # 针对引入的 EMQX 组件的配置 |
| 38 | # ==================================== | 38 | # ==================================== |
| 39 | emqx: | 39 | emqx: |
| 40 | - enabled: true | 40 | + enabled: false |
| 41 | mqtt-ssl: false | 41 | mqtt-ssl: false |
| 42 | mqtt-topics: | 42 | mqtt-topics: |
| 43 | - "/sys/#" # 系统主题 | 43 | - "/sys/#" # 系统主题 |
| 44 | 44 | ||
| 45 | # 消息总线配置 | 45 | # 消息总线配置 |
| 46 | message-bus: | 46 | message-bus: |
| 47 | - type: rocketmq # 消息总线的类型 | 47 | + type: redis # 消息总线的类型 |
| 48 | 48 | ||
| 49 | --- #################### 日志相关配置 #################### | 49 | --- #################### 日志相关配置 #################### |
| 50 | 50 |
yudao-server/src/main/resources/application.yaml
| @@ -313,6 +313,6 @@ yudao: | @@ -313,6 +313,6 @@ yudao: | ||
| 313 | customer: E77DF18BE109F454A5CD319E44BF5177 | 313 | customer: E77DF18BE109F454A5CD319E44BF5177 |
| 314 | iot: | 314 | iot: |
| 315 | message-bus: | 315 | message-bus: |
| 316 | - type: rocketmq # 消息总线的类型 | 316 | + type: redis # 消息总线的类型 |
| 317 | 317 | ||
| 318 | debug: false | 318 | debug: false |
| 319 | \ No newline at end of file | 319 | \ No newline at end of file |