9 小时以前 8f3bf7050e65fdbe55eaad74fde307c57dab960e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package cn.iocoder.yudao.module.iot.core.messagebus.config;
 
import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
import cn.iocoder.yudao.framework.mq.redis.core.job.RedisPendingMessageResendJob;
import cn.iocoder.yudao.framework.mq.redis.core.job.RedisStreamMessageCleanupJob;
import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessage;
import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener;
import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
import cn.iocoder.yudao.module.iot.core.messagebus.core.kafka.IotKafkaMessageBus;
import cn.iocoder.yudao.module.iot.core.messagebus.core.local.IotLocalMessageBus;
import cn.iocoder.yudao.module.iot.core.messagebus.core.rabbitmq.IotRabbitMQMessageBus;
import cn.iocoder.yudao.module.iot.core.messagebus.core.redis.IotRedisMessageBus;
import cn.iocoder.yudao.module.iot.core.messagebus.core.rocketmq.IotRocketMQMessageBus;
import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.autoconfigure.RocketMQProperties;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.kafka.autoconfigure.KafkaProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
 
import java.util.List;
 
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 
/**
 * IoT 消息总线自动配置
 *
 * @author 芋道源码
 */
@AutoConfiguration
@EnableConfigurationProperties(IotMessageBusProperties.class)
@Slf4j
public class IotMessageBusAutoConfiguration {
 
    @Bean
    public IotDeviceMessageProducer deviceMessageProducer(IotMessageBus messageBus) {
        return new IotDeviceMessageProducer(messageBus);
    }
 
    // ==================== Local 实现 ====================
 
    @Configuration
    @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "local", matchIfMissing = true)
    public static class IotLocalMessageBusConfiguration {
 
        @Bean
        public IotLocalMessageBus iotLocalMessageBus(ApplicationContext applicationContext) {
            log.info("[iotLocalMessageBus][创建 IoT Local 消息总线]");
            return new IotLocalMessageBus(applicationContext);
        }
 
    }
 
    // ==================== RocketMQ 实现 ====================
 
    @Configuration
    @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "rocketmq")
    @ConditionalOnClass(RocketMQTemplate.class)
    public static class IotRocketMQMessageBusConfiguration {
 
        @Bean
        public IotRocketMQMessageBus iotRocketMQMessageBus(RocketMQProperties rocketMQProperties,
                                                           RocketMQTemplate rocketMQTemplate) {
            log.info("[iotRocketMQMessageBus][创建 IoT RocketMQ 消息总线]");
            return new IotRocketMQMessageBus(rocketMQProperties, rocketMQTemplate);
        }
 
    }
 
    // ==================== Kafka 实现 ====================
 
    @Configuration
    @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "kafka")
    @ConditionalOnClass(KafkaTemplate.class)
    public static class IotKafkaMessageBusConfiguration {
 
        @Bean
        public IotKafkaMessageBus iotKafkaMessageBus(KafkaProperties kafkaProperties) {
            log.info("[iotKafkaMessageBus][创建 IoT Kafka 消息总线]");
            return new IotKafkaMessageBus(kafkaProperties);
        }
 
    }
 
    // ==================== Redis 实现 ====================
 
    /**
     * 特殊:由于 YudaoRedisMQConsumerAutoConfiguration 关于 Redis stream 的消费是动态注册,所以这里只能拷贝相关的逻辑!!!
     *
     * @see cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQConsumerAutoConfiguration
     */
    @Configuration
    @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "redis")
    @ConditionalOnClass(RedisTemplate.class)
    public static class IotRedisMessageBusConfiguration {
 
        @Bean
        public IotRedisMessageBus iotRedisMessageBus(StringRedisTemplate redisTemplate) {
            log.info("[iotRedisMessageBus][创建 IoT Redis 消息总线]");
            return new IotRedisMessageBus(redisTemplate);
        }
 
        /**
         * 创建 Redis Stream 重新消费的任务
         */
        @Bean
        public RedisPendingMessageResendJob iotRedisPendingMessageResendJob(IotRedisMessageBus messageBus,
                                                                            RedisMQTemplate redisTemplate,
                                                                            RedissonClient redissonClient) {
            List<AbstractRedisStreamMessageListener<?>> listeners = getListeners(messageBus);
            return new RedisPendingMessageResendJob(listeners, redisTemplate, redissonClient,
                    RedisPendingMessageResendJob.IOT_RESEND_LOCK_KEY);
        }
 
        /**
         * 创建 Redis Stream 消息清理任务
         */
        @Bean
        public RedisStreamMessageCleanupJob iotRedisStreamMessageCleanupJob(IotRedisMessageBus messageBus,
                                                                            RedisMQTemplate redisTemplate,
                                                                            RedissonClient redissonClient) {
            List<AbstractRedisStreamMessageListener<?>> listeners = getListeners(messageBus);
            return new RedisStreamMessageCleanupJob(listeners, redisTemplate, redissonClient,
                    RedisStreamMessageCleanupJob.IOT_CLEANUP_LOCK_KEY);
        }
 
        private List<AbstractRedisStreamMessageListener<?>> getListeners(IotRedisMessageBus messageBus) {
            return convertList(messageBus.getSubscribers(), subscriber ->
                    new AbstractRedisStreamMessageListener<>(subscriber.getTopic(), subscriber.getGroup()) {
 
                        @Override
                        public void onMessage(AbstractRedisStreamMessage message) {
                            throw new UnsupportedOperationException("不应该调用!!!");
                        }
                    });
        }
 
    }
 
    // ==================== RabbitMQ 实现 ====================
 
    @Configuration
    @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "rabbitmq")
    @ConditionalOnClass(RabbitTemplate.class)
    public static class IotRabbitMQMessageBusConfiguration {
 
        @Bean
        @ConditionalOnMissingBean
        public RabbitAdmin rabbitAdmin(RabbitTemplate rabbitTemplate) {
            return new RabbitAdmin(rabbitTemplate);
        }
 
        @Bean
        public IotRabbitMQMessageBus iotRabbitMQMessageBus(RabbitTemplate rabbitTemplate, RabbitAdmin rabbitAdmin) {
            log.info("[iotRabbitMQMessageBus][创建 IoT RabbitMQ 消息总线]");
            return new IotRabbitMQMessageBus(rabbitTemplate, rabbitAdmin);
        }
 
    }
 
}