Commit c066ea46f9881e8ccf7b7abf3b2add8a38f9ea84

Authored by YunaiV
1 parent d048daf7

mq 重构:默认的 redis 实现:

1)默认 channel 和 stream key
2)移除 enabled 开关,通过 listener 是否存在来实现
3)调整包名,为接入 rocketmq 作为 mq 实现做准备
Showing 15 changed files with 51 additions and 114 deletions
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/TenantRedisMessageInterceptor.java
1 package cn.iocoder.yudao.framework.tenant.core.mq; 1 package cn.iocoder.yudao.framework.tenant.core.mq;
2 2
3 import cn.hutool.core.util.StrUtil; 3 import cn.hutool.core.util.StrUtil;
4 -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;  
5 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage; 4 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  5 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
6 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; 6 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
7 7
8 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; 8 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java
1 /** 1 /**
  2 + * TODO 芋艿:调整注释
2 * 消息队列,基于 Redis 提供: 3 * 消息队列,基于 Redis 提供:
3 * 1. 基于 Pub/Sub 实现广播消费 4 * 1. 基于 Pub/Sub 实现广播消费
4 * 2. 基于 Stream 实现集群消费 5 * 2. 基于 Stream 实现集群消费
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/config/YudaoMQAutoConfiguration.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQAutoConfiguration.java
1 -package cn.iocoder.yudao.framework.mq.config; 1 +package cn.iocoder.yudao.framework.mq.redis.config;
2 2
3 import cn.hutool.core.map.MapUtil; 3 import cn.hutool.core.map.MapUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
5 import cn.hutool.system.SystemUtil; 5 import cn.hutool.system.SystemUtil;
6 import cn.iocoder.yudao.framework.common.enums.DocumentEnum; 6 import cn.iocoder.yudao.framework.common.enums.DocumentEnum;
7 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
8 -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;  
9 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
10 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;  
11 -import cn.iocoder.yudao.framework.mq.job.RedisPendingMessageResendJob; 7 +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
  8 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  9 +import cn.iocoder.yudao.framework.mq.redis.core.job.RedisPendingMessageResendJob;
  10 +import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractChannelMessageListener;
  11 +import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractStreamMessageListener;
12 import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; 12 import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
13 import lombok.extern.slf4j.Slf4j; 13 import lombok.extern.slf4j.Slf4j;
14 import org.redisson.api.RedissonClient; 14 import org.redisson.api.RedissonClient;
15 import org.springframework.beans.factory.annotation.Value; 15 import org.springframework.beans.factory.annotation.Value;
16 import org.springframework.boot.autoconfigure.AutoConfiguration; 16 import org.springframework.boot.autoconfigure.AutoConfiguration;
17 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 17 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
18 -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;  
19 import org.springframework.context.annotation.Bean; 18 import org.springframework.context.annotation.Bean;
20 import org.springframework.data.redis.connection.RedisServerCommands; 19 import org.springframework.data.redis.connection.RedisServerCommands;
21 import org.springframework.data.redis.connection.stream.Consumer; 20 import org.springframework.data.redis.connection.stream.Consumer;
@@ -27,7 +26,6 @@ import org.springframework.data.redis.core.RedisTemplate; @@ -27,7 +26,6 @@ import org.springframework.data.redis.core.RedisTemplate;
27 import org.springframework.data.redis.core.StringRedisTemplate; 26 import org.springframework.data.redis.core.StringRedisTemplate;
28 import org.springframework.data.redis.listener.ChannelTopic; 27 import org.springframework.data.redis.listener.ChannelTopic;
29 import org.springframework.data.redis.listener.RedisMessageListenerContainer; 28 import org.springframework.data.redis.listener.RedisMessageListenerContainer;
30 -import org.springframework.data.redis.stream.DefaultStreamMessageListenerContainerX;  
31 import org.springframework.data.redis.stream.StreamMessageListenerContainer; 29 import org.springframework.data.redis.stream.StreamMessageListenerContainer;
32 import org.springframework.scheduling.annotation.EnableScheduling; 30 import org.springframework.scheduling.annotation.EnableScheduling;
33 31
@@ -42,7 +40,7 @@ import java.util.Properties; @@ -42,7 +40,7 @@ import java.util.Properties;
42 @Slf4j 40 @Slf4j
43 @EnableScheduling // 启用定时任务,用于 RedisPendingMessageResendJob 重发消息 41 @EnableScheduling // 启用定时任务,用于 RedisPendingMessageResendJob 重发消息
44 @AutoConfiguration(after = YudaoRedisAutoConfiguration.class) 42 @AutoConfiguration(after = YudaoRedisAutoConfiguration.class)
45 -public class YudaoMQAutoConfiguration { 43 +public class YudaoRedisMQAutoConfiguration {
46 44
47 @Bean 45 @Bean
48 public RedisMQTemplate redisMQTemplate(StringRedisTemplate redisTemplate, 46 public RedisMQTemplate redisMQTemplate(StringRedisTemplate redisTemplate,
@@ -60,7 +58,6 @@ public class YudaoMQAutoConfiguration { @@ -60,7 +58,6 @@ public class YudaoMQAutoConfiguration {
60 */ 58 */
61 @Bean(initMethod = "start", destroyMethod = "stop") 59 @Bean(initMethod = "start", destroyMethod = "stop")
62 @ConditionalOnBean(AbstractChannelMessageListener.class) // 只有 AbstractChannelMessageListener 存在的时候,才需要注册 Redis pubsub 监听 60 @ConditionalOnBean(AbstractChannelMessageListener.class) // 只有 AbstractChannelMessageListener 存在的时候,才需要注册 Redis pubsub 监听
63 - @ConditionalOnProperty(prefix = "yudao.mq.redis.pubsub", value = "enable", matchIfMissing = true) // 允许使用 yudao.mq.redis.pubsub.enable=false 禁用多租户  
64 public RedisMessageListenerContainer redisMessageListenerContainer( 61 public RedisMessageListenerContainer redisMessageListenerContainer(
65 RedisMQTemplate redisMQTemplate, List<AbstractChannelMessageListener<?>> listeners) { 62 RedisMQTemplate redisMQTemplate, List<AbstractChannelMessageListener<?>> listeners) {
66 // 创建 RedisMessageListenerContainer 对象 63 // 创建 RedisMessageListenerContainer 对象
@@ -82,7 +79,6 @@ public class YudaoMQAutoConfiguration { @@ -82,7 +79,6 @@ public class YudaoMQAutoConfiguration {
82 */ 79 */
83 @Bean 80 @Bean
84 @ConditionalOnBean(AbstractStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听 81 @ConditionalOnBean(AbstractStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
85 - @ConditionalOnProperty(prefix = "yudao.mq.redis.stream", value = "enable", matchIfMissing = true) // 允许使用 yudao.mq.redis.stream.enable=false 禁用多租户  
86 public RedisPendingMessageResendJob redisPendingMessageResendJob(List<AbstractStreamMessageListener<?>> listeners, 82 public RedisPendingMessageResendJob redisPendingMessageResendJob(List<AbstractStreamMessageListener<?>> listeners,
87 RedisMQTemplate redisTemplate, 83 RedisMQTemplate redisTemplate,
88 @Value("${spring.application.name}") String groupName, 84 @Value("${spring.application.name}") String groupName,
@@ -92,12 +88,11 @@ public class YudaoMQAutoConfiguration { @@ -92,12 +88,11 @@ public class YudaoMQAutoConfiguration {
92 88
93 /** 89 /**
94 * 创建 Redis Stream 集群消费的容器 90 * 创建 Redis Stream 集群消费的容器
95 - * <p>  
96 - * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html 91 + *
  92 + * 基础知识:<a href="https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html">Redis Stream 的 xreadgroup 命令</a>
97 */ 93 */
98 @Bean(initMethod = "start", destroyMethod = "stop") 94 @Bean(initMethod = "start", destroyMethod = "stop")
99 @ConditionalOnBean(AbstractStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听 95 @ConditionalOnBean(AbstractStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
100 - @ConditionalOnProperty(prefix = "yudao.mq.redis.stream", value = "enable", matchIfMissing = true) // 允许使用 yudao.mq.redis.stream.enable=false 禁用多租户  
101 public StreamMessageListenerContainer<String, ObjectRecord<String, String>> redisStreamMessageListenerContainer( 96 public StreamMessageListenerContainer<String, ObjectRecord<String, String>> redisStreamMessageListenerContainer(
102 RedisMQTemplate redisMQTemplate, List<AbstractStreamMessageListener<?>> listeners) { 97 RedisMQTemplate redisMQTemplate, List<AbstractStreamMessageListener<?>> listeners) {
103 RedisTemplate<String, ?> redisTemplate = redisMQTemplate.getRedisTemplate(); 98 RedisTemplate<String, ?> redisTemplate = redisMQTemplate.getRedisTemplate();
@@ -111,8 +106,7 @@ public class YudaoMQAutoConfiguration { @@ -111,8 +106,7 @@ public class YudaoMQAutoConfiguration {
111 .build(); 106 .build();
112 // 创建 container 对象 107 // 创建 container 对象
113 StreamMessageListenerContainer<String, ObjectRecord<String, String>> container = 108 StreamMessageListenerContainer<String, ObjectRecord<String, String>> container =
114 -// StreamMessageListenerContainer.create(redisTemplate.getRequiredConnectionFactory(), containerOptions);  
115 - DefaultStreamMessageListenerContainerX.create(redisMQTemplate.getRedisTemplate().getRequiredConnectionFactory(), containerOptions); 109 + StreamMessageListenerContainer.create(redisMQTemplate.getRedisTemplate().getRequiredConnectionFactory(), containerOptions);
116 110
117 // 第二步,注册监听器,消费对应的 Stream 主题 111 // 第二步,注册监听器,消费对应的 Stream 主题
118 String consumerName = buildConsumerName(); 112 String consumerName = buildConsumerName();
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/RedisMQTemplate.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/RedisMQTemplate.java
1 -package cn.iocoder.yudao.framework.mq.core; 1 +package cn.iocoder.yudao.framework.mq.redis.core;
2 2
3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
4 -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;  
5 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;  
6 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;  
7 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage; 4 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  5 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
  6 +import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractChannelMessage;
  7 +import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractStreamMessage;
8 import lombok.AllArgsConstructor; 8 import lombok.AllArgsConstructor;
9 import lombok.Getter; 9 import lombok.Getter;
10 import org.springframework.data.redis.connection.stream.RecordId; 10 import org.springframework.data.redis.connection.stream.RecordId;
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/interceptor/RedisMessageInterceptor.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/interceptor/RedisMessageInterceptor.java
1 -package cn.iocoder.yudao.framework.mq.core.interceptor; 1 +package cn.iocoder.yudao.framework.mq.redis.core.interceptor;
2 2
3 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage; 3 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
4 4
5 /** 5 /**
6 * {@link AbstractRedisMessage} 消息拦截器 6 * {@link AbstractRedisMessage} 消息拦截器
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/job/RedisPendingMessageResendJob.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java
1 -package cn.iocoder.yudao.framework.mq.job; 1 +package cn.iocoder.yudao.framework.mq.redis.core.job;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
5 -import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener; 4 +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
  5 +import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractStreamMessageListener;
6 import lombok.AllArgsConstructor; 6 import lombok.AllArgsConstructor;
7 import lombok.extern.slf4j.Slf4j; 7 import lombok.extern.slf4j.Slf4j;
8 import org.redisson.api.RLock; 8 import org.redisson.api.RLock;
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/message/AbstractRedisMessage.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/message/AbstractRedisMessage.java
1 -package cn.iocoder.yudao.framework.mq.core.message; 1 +package cn.iocoder.yudao.framework.mq.redis.core.message;
2 2
3 import lombok.Data; 3 import lombok.Data;
4 4
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/pubsub/AbstractChannelMessage.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractChannelMessage.java
1 -package cn.iocoder.yudao.framework.mq.core.pubsub; 1 +package cn.iocoder.yudao.framework.mq.redis.core.pubsub;
2 2
3 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage; 3 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
4 import com.fasterxml.jackson.annotation.JsonIgnore; 4 import com.fasterxml.jackson.annotation.JsonIgnore;
5 5
6 /** 6 /**
@@ -11,11 +11,13 @@ import com.fasterxml.jackson.annotation.JsonIgnore; @@ -11,11 +11,13 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
11 public abstract class AbstractChannelMessage extends AbstractRedisMessage { 11 public abstract class AbstractChannelMessage extends AbstractRedisMessage {
12 12
13 /** 13 /**
14 - * 获得 Redis Channel 14 + * 获得 Redis Channel,默认使用类名
15 * 15 *
16 * @return Channel 16 * @return Channel
17 */ 17 */
18 @JsonIgnore // 避免序列化。原因是,Redis 发布 Channel 消息的时候,已经会指定。 18 @JsonIgnore // 避免序列化。原因是,Redis 发布 Channel 消息的时候,已经会指定。
19 - public abstract String getChannel(); 19 + public String getChannel() {
  20 + return getClass().getSimpleName();
  21 + }
20 22
21 } 23 }
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/pubsub/AbstractChannelMessageListener.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractChannelMessageListener.java
1 -package cn.iocoder.yudao.framework.mq.core.pubsub; 1 +package cn.iocoder.yudao.framework.mq.redis.core.pubsub;
2 2
3 import cn.hutool.core.util.TypeUtil; 3 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.framework.mq.core.RedisMQTemplate;  
6 -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;  
7 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage; 5 +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
  6 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  7 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
8 import lombok.Setter; 8 import lombok.Setter;
9 import lombok.SneakyThrows; 9 import lombok.SneakyThrows;
10 import org.springframework.data.redis.connection.Message; 10 import org.springframework.data.redis.connection.Message;
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/stream/AbstractStreamMessage.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractStreamMessage.java
1 -package cn.iocoder.yudao.framework.mq.core.stream; 1 +package cn.iocoder.yudao.framework.mq.redis.core.stream;
2 2
3 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage; 3 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
4 import com.fasterxml.jackson.annotation.JsonIgnore; 4 import com.fasterxml.jackson.annotation.JsonIgnore;
5 5
6 /** 6 /**
@@ -11,11 +11,13 @@ import com.fasterxml.jackson.annotation.JsonIgnore; @@ -11,11 +11,13 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
11 public abstract class AbstractStreamMessage extends AbstractRedisMessage { 11 public abstract class AbstractStreamMessage extends AbstractRedisMessage {
12 12
13 /** 13 /**
14 - * 获得 Redis Stream Key 14 + * 获得 Redis Stream Key,默认使用类名
15 * 15 *
16 * @return Channel 16 * @return Channel
17 */ 17 */
18 @JsonIgnore // 避免序列化 18 @JsonIgnore // 避免序列化
19 - public abstract String getStreamKey(); 19 + public String getStreamKey() {
  20 + return getClass().getSimpleName();
  21 + }
20 22
21 } 23 }
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/stream/AbstractStreamMessageListener.java renamed to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractStreamMessageListener.java
1 -package cn.iocoder.yudao.framework.mq.core.stream; 1 +package cn.iocoder.yudao.framework.mq.redis.core.stream;
2 2
3 import cn.hutool.core.util.TypeUtil; 3 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.framework.mq.core.RedisMQTemplate;  
6 -import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;  
7 -import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage; 5 +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
  6 +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
  7 +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
8 import lombok.Getter; 8 import lombok.Getter;
9 import lombok.Setter; 9 import lombok.Setter;
10 import lombok.SneakyThrows; 10 import lombok.SneakyThrows;
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/package-info.java 0 → 100644
  1 +/**
  2 + * 消息队列,基于 Redis 提供:
  3 + * 1. 基于 Pub/Sub 实现广播消费
  4 + * 2. 基于 Stream 实现集群消费
  5 + */
  6 +package cn.iocoder.yudao.framework.mq.redis;
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/org/springframework/data/redis/stream/DefaultStreamMessageListenerContainerX.java deleted
1 -package org.springframework.data.redis.stream;  
2 -  
3 -import cn.hutool.core.util.ReflectUtil;  
4 -import org.springframework.data.redis.connection.RedisConnectionFactory;  
5 -import org.springframework.data.redis.connection.stream.ByteRecord;  
6 -import org.springframework.data.redis.connection.stream.ReadOffset;  
7 -import org.springframework.data.redis.connection.stream.Record;  
8 -import org.springframework.util.Assert;  
9 -  
10 -import java.util.Collections;  
11 -import java.util.List;  
12 -import java.util.function.Function;  
13 -  
14 -/**  
15 - * 拓展 DefaultStreamMessageListenerContainer 实现,解决 Spring Data Redis + Redisson 结合使用时,Redisson 在 Stream 获得不到数据时,返回 null 而不是空 List,导致 NPE 异常。  
16 - * 对应 issue:https://github.com/spring-projects/spring-data-redis/issues/2147 和 https://github.com/redisson/redisson/issues/4006  
17 - * 目前看下来 Spring Data Redis 不肯加 null 判断,Redisson 暂时也没改返回 null 到空 List 的打算,所以暂时只能自己改,哽咽!  
18 - *  
19 - * @author 芋道源码  
20 - */  
21 -public class DefaultStreamMessageListenerContainerX<K, V extends Record<K, ?>> extends DefaultStreamMessageListenerContainer<K, V> {  
22 -  
23 - /**  
24 - * 参考 {@link StreamMessageListenerContainer#create(RedisConnectionFactory, StreamMessageListenerContainerOptions)} 的实现  
25 - */  
26 - public static <K, V extends Record<K, ?>> StreamMessageListenerContainer<K, V> create(RedisConnectionFactory connectionFactory, StreamMessageListenerContainer.StreamMessageListenerContainerOptions<K, V> options) {  
27 - Assert.notNull(connectionFactory, "RedisConnectionFactory must not be null!");  
28 - Assert.notNull(options, "StreamMessageListenerContainerOptions must not be null!");  
29 - return new DefaultStreamMessageListenerContainerX<>(connectionFactory, options);  
30 - }  
31 -  
32 - public DefaultStreamMessageListenerContainerX(RedisConnectionFactory connectionFactory, StreamMessageListenerContainerOptions<K, V> containerOptions) {  
33 - super(connectionFactory, containerOptions);  
34 - }  
35 -  
36 - /**  
37 - * 参考 {@link DefaultStreamMessageListenerContainer#register(StreamReadRequest, StreamListener)} 的实现  
38 - */  
39 - @Override  
40 - public Subscription register(StreamReadRequest<K> streamRequest, StreamListener<K, V> listener) {  
41 - return this.doRegisterX(getReadTaskX(streamRequest, listener));  
42 - }  
43 -  
44 - @SuppressWarnings("unchecked")  
45 - private StreamPollTask<K, V> getReadTaskX(StreamReadRequest<K> streamRequest, StreamListener<K, V> listener) {  
46 - StreamPollTask<K, V> task = ReflectUtil.invoke(this, "getReadTask", streamRequest, listener);  
47 - // 修改 readFunction 方法  
48 - Function<ReadOffset, List<ByteRecord>> readFunction = (Function<ReadOffset, List<ByteRecord>>) ReflectUtil.getFieldValue(task, "readFunction");  
49 - ReflectUtil.setFieldValue(task, "readFunction", (Function<ReadOffset, List<ByteRecord>>) readOffset -> {  
50 - List<ByteRecord> records = readFunction.apply(readOffset);  
51 - //【重点】保证 records 不是空,避免 NPE 的问题!!!  
52 - return records != null ? records : Collections.emptyList();  
53 - });  
54 - return task;  
55 - }  
56 -  
57 - private Subscription doRegisterX(Task task) {  
58 - return ReflectUtil.invoke(this, "doRegister", task);  
59 - }  
60 -  
61 -}  
62 -  
yudao-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
1 -cn.iocoder.yudao.framework.mq.config.YudaoMQAutoConfiguration  
2 \ No newline at end of file 1 \ No newline at end of file
  2 +cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQAutoConfiguration
yudao-server/src/main/resources/application.yaml
@@ -145,12 +145,6 @@ yudao: @@ -145,12 +145,6 @@ yudao:
145 - cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants 145 - cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants
146 - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants 146 - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants
147 - cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants 147 - cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants
148 - mq:  
149 - redis:  
150 - pubsub:  
151 - enable: false # 是否开启 Redis pubsub 广播消费,默认为 true。这里设置成 false,可以按需开启  
152 - stream:  
153 - enable: false # 是否开启 Redis stream 集群消费,默认为 true。这里设置成 false,可以按需开启  
154 tenant: # 多租户相关配置项 148 tenant: # 多租户相关配置项
155 enable: true 149 enable: true
156 ignore-urls: 150 ignore-urls: