From efae1c914b98fd4b2e83f36955fdf382ddf6344f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Thu, 29 Jan 2026 09:41:17 +0000 Subject: [PATCH] =?UTF-8?q?Revert=20"update=20=E4=BD=BF=E7=94=A8Spring=20R?= =?UTF-8?q?edis=20Data=E8=87=AA=E5=8A=A8=E9=85=8D=E7=BD=AE=E9=A1=B9?= =?UTF-8?q?=E4=BC=98=E5=8C=96Redisson=204.X=E9=85=8D=E7=BD=AE=E6=B5=81?= =?UTF-8?q?=E7=A8=8B"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 7c3a5c4a1d6dfe639b2adb7352f24b3e97fbb70a. --- .../src/main/resources/application-dev.yml | 45 +++--- .../src/main/resources/application-prod.yml | 45 +++--- ruoyi-common/ruoyi-common-redis/pom.xml | 4 +- .../common/redis/config/RedisConfig.java | 148 ++++++++++-------- .../config/properties/RedissonProperties.java | 135 ++++++++++++++++ .../redis/handler/KeyPrefixHandler.java | 11 +- 6 files changed, 278 insertions(+), 110 deletions(-) create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 7768f4afd..1b52fab96 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -107,28 +107,29 @@ spring.data: timeout: 10s # 是否开启ssl ssl.enabled: false - # redisson 配置 官方文档:https://redisson.pro/docs/integration-with-spring/#spring-boot-starter - redisson: - # redis key前缀 - keyPrefix: - # 线程池数量 - threads: 4 - # Netty线程池数量 - nettyThreads: 8 - # 单节点配置 - singleServerConfig: - # 客户端名称 不能用中文 - clientName: RuoYi-Vue-Plus - # 最小空闲连接数 - connectionMinimumIdleSize: 8 - # 连接池大小 - connectionPoolSize: 32 - # 连接空闲超时,单位:毫秒 - idleConnectionTimeout: 10000 - # 命令等待超时,单位:毫秒 - timeout: 3000 - # 发布和订阅连接池大小 - subscriptionConnectionPoolSize: 50 + +# redisson 配置 +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 4 + # Netty线程池数量 + nettyThreads: 8 + # 单节点配置 + singleServerConfig: + # 客户端名称 不能用中文 + clientName: RuoYi-Vue-Plus + # 最小空闲连接数 + connectionMinimumIdleSize: 8 + # 连接池大小 + connectionPoolSize: 32 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 --- # mail 邮件发送 mail: diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml index 6fc718f05..d77ddf57c 100644 --- a/ruoyi-admin/src/main/resources/application-prod.yml +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -110,28 +110,29 @@ spring.data: timeout: 10s # 是否开启ssl ssl.enabled: false - # redisson 配置 官方文档:https://redisson.pro/docs/integration-with-spring/#spring-boot-starter - redisson: - # redis key前缀 - keyPrefix: - # 线程池数量 - threads: 16 - # Netty线程池数量 - nettyThreads: 32 - # 单节点配置 - singleServerConfig: - # 客户端名称 不能用中文 - clientName: RuoYi-Vue-Plus - # 最小空闲连接数 - connectionMinimumIdleSize: 32 - # 连接池大小 - connectionPoolSize: 64 - # 连接空闲超时,单位:毫秒 - idleConnectionTimeout: 10000 - # 命令等待超时,单位:毫秒 - timeout: 3000 - # 发布和订阅连接池大小 - subscriptionConnectionPoolSize: 50 + +# redisson 配置 +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 单节点配置 + singleServerConfig: + # 客户端名称 不能用中文 + clientName: RuoYi-Vue-Plus + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 --- # mail 邮件发送 mail: diff --git a/ruoyi-common/ruoyi-common-redis/pom.xml b/ruoyi-common/ruoyi-common-redis/pom.xml index b42603fa1..12cb577f7 100644 --- a/ruoyi-common/ruoyi-common-redis/pom.xml +++ b/ruoyi-common/ruoyi-common-redis/pom.xml @@ -45,8 +45,8 @@ - tools.jackson.core - jackson-databind + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java index a11333ac4..2e82330f2 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java @@ -1,25 +1,28 @@ package org.dromara.common.redis.config; +import cn.hutool.core.util.ObjectUtil; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.redis.config.properties.RedissonProperties; import org.dromara.common.redis.handler.KeyPrefixHandler; import org.dromara.common.redis.handler.RedisExceptionHandler; import org.redisson.client.codec.StringCodec; import org.redisson.codec.CompositeCodec; -import org.redisson.codec.TypedJsonJackson3Codec; +import org.redisson.codec.TypedJsonJacksonCodec; import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.core.task.VirtualThreadTaskExecutor; -import tools.jackson.databind.DefaultTyping; -import tools.jackson.databind.ext.javatime.deser.LocalDateTimeDeserializer; -import tools.jackson.databind.ext.javatime.ser.LocalDateTimeSerializer; -import tools.jackson.databind.json.JsonMapper; -import tools.jackson.databind.jsontype.DefaultBaseTypeLimitingValidator; -import tools.jackson.databind.module.SimpleModule; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -32,45 +35,68 @@ import java.util.TimeZone; */ @Slf4j @AutoConfiguration +@EnableConfigurationProperties(RedissonProperties.class) public class RedisConfig { - /** - * redisson 自定义配置 (更多相关配置项目请参阅 RedissonProperties/RedissonAutoConfigurationV4 和 DataRedisProperties) - * - * @see org.redisson.spring.starter.RedissonProperties - * @see org.redisson.spring.starter.RedissonAutoConfigurationV4 - * @see org.springframework.boot.data.redis.autoconfigure.DataRedisProperties - * - * @param keyPrefix redis缓存key前缀 - */ - @Bean - public RedissonAutoConfigurationCustomizer redissonCustomizer(@Value("${spring.data.redis.redisson.keyPrefix}") String keyPrefix) { + @Autowired + private RedissonProperties redissonProperties; + @Bean + public RedissonAutoConfigurationCustomizer redissonCustomizer() { return config -> { - SimpleModule simpleModule = new SimpleModule(); + JavaTimeModule javaTimeModule = new JavaTimeModule(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter)); - simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); - JsonMapper jsonMapper = JsonMapper.builder() - .addModules(simpleModule) - .defaultTimeZone(TimeZone.getDefault()) - .changeDefaultVisibility(visibilityChecker -> visibilityChecker.withVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY)) - // 指定序列化输入的类型,类必须是非final修饰的。序列化时将对象全类名一起保存下来 - // LaissezFaireSubTypeValidator 在 Jackson 3.X 中被禁止外部引用,此处使用 DefaultBaseTypeLimitingValidator 替代,两者在行为上可能会有所差异,但一般情况下无影响 - .activateDefaultTyping(new DefaultBaseTypeLimitingValidator(), DefaultTyping.NON_FINAL) - .build(); + javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter)); + javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); + JsonMapper om = new JsonMapper(); + om.registerModule(javaTimeModule); + om.setTimeZone(TimeZone.getDefault()); + om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + // 指定序列化输入的类型,类必须是非final修饰的。序列化时将对象全类名一起保存下来 + om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); // org.apache.fory.logging.LoggerFactory 包别引入错了 // LoggerFactory.useSlf4jLogging(true); // ForyCodec foryCodec = new ForyCodec(); // CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, foryCodec, foryCodec); - TypedJsonJackson3Codec jsonCodec = new TypedJsonJackson3Codec(Object.class, jsonMapper); + TypedJsonJacksonCodec jsonCodec = new TypedJsonJacksonCodec(Object.class, om); // 组合序列化 key 使用 String 内容使用通用 json 格式 CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, jsonCodec, jsonCodec); - config.setCodec(codec); + config.setThreads(redissonProperties.getThreads()) + .setNettyThreads(redissonProperties.getNettyThreads()) + // 缓存 Lua 脚本 减少网络传输(redisson 大部分的功能都是基于 Lua 脚本实现) + .setUseScriptCache(true) + //设置redis key前缀 + .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) + .setCodec(codec); if (SpringUtils.isVirtual()) { config.setNettyExecutor(new VirtualThreadTaskExecutor("redisson-")); } - config.setNameMapper(new KeyPrefixHandler(keyPrefix)); + RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig(); + if (ObjectUtil.isNotNull(singleServerConfig)) { + // 使用单机模式 + config.useSingleServer() + .setTimeout(singleServerConfig.getTimeout()) + .setClientName(singleServerConfig.getClientName()) + .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout()) + .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize()) + .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize()) + .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize()); + } + // 集群配置方式 参考下方注释 + RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig(); + if (ObjectUtil.isNotNull(clusterServersConfig)) { + config.useClusterServers() + .setTimeout(clusterServersConfig.getTimeout()) + .setClientName(clusterServersConfig.getClientName()) + .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout()) + .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize()) + .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize()) + .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize()) + .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize()) + .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize()) + .setReadMode(clusterServersConfig.getReadMode()) + .setSubscriptionMode(clusterServersConfig.getSubscriptionMode()); + } log.info("初始化 redis 配置"); }; } @@ -100,34 +126,34 @@ public class RedisConfig { * timeout: 10s * # 是否开启ssl * ssl.enabled: false - * # redisson配置 - * redisson: - * # 线程池数量 - * threads: 16 - * # Netty线程池数量 - * nettyThreads: 32 - * # 集群配置 - * clusterServersConfig: - * # 客户端名称 - * clientName: ${ruoyi.name} - * # master最小空闲连接数 - * masterConnectionMinimumIdleSize: 32 - * # master连接池大小 - * masterConnectionPoolSize: 64 - * # slave最小空闲连接数 - * slaveConnectionMinimumIdleSize: 32 - * # slave连接池大小 - * slaveConnectionPoolSize: 64 - * # 连接空闲超时,单位:毫秒 - * idleConnectionTimeout: 10000 - * # 命令等待超时,单位:毫秒 - * timeout: 3000 - * # 发布和订阅连接池大小 - * subscriptionConnectionPoolSize: 50 - * # 读取模式 - * readMode: "SLAVE" - * # 订阅模式 - * subscriptionMode: "MASTER" + * + * redisson: + * # 线程池数量 + * threads: 16 + * # Netty线程池数量 + * nettyThreads: 32 + * # 集群配置 + * clusterServersConfig: + * # 客户端名称 + * clientName: ${ruoyi.name} + * # master最小空闲连接数 + * masterConnectionMinimumIdleSize: 32 + * # master连接池大小 + * masterConnectionPoolSize: 64 + * # slave最小空闲连接数 + * slaveConnectionMinimumIdleSize: 32 + * # slave连接池大小 + * slaveConnectionPoolSize: 64 + * # 连接空闲超时,单位:毫秒 + * idleConnectionTimeout: 10000 + * # 命令等待超时,单位:毫秒 + * timeout: 3000 + * # 发布和订阅连接池大小 + * subscriptionConnectionPoolSize: 50 + * # 读取模式 + * readMode: "SLAVE" + * # 订阅模式 + * subscriptionMode: "MASTER" */ } diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java new file mode 100644 index 000000000..ebec7861a --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java @@ -0,0 +1,135 @@ +package org.dromara.common.redis.config.properties; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.redisson.config.ReadMode; +import org.redisson.config.SubscriptionMode; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Redisson 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "redisson") +public class RedissonProperties { + + /** + * redis缓存key前缀 + */ + private String keyPrefix; + + /** + * 线程池数量,默认值 = 当前处理核数量 * 2 + */ + private int threads; + + /** + * Netty线程池数量,默认值 = 当前处理核数量 * 2 + */ + private int nettyThreads; + + /** + * 单机服务配置 + */ + private SingleServerConfig singleServerConfig; + + /** + * 集群服务配置 + */ + private ClusterServersConfig clusterServersConfig; + + @Data + @NoArgsConstructor + public static class SingleServerConfig { + + /** + * 客户端名称 + */ + private String clientName; + + /** + * 最小空闲连接数 + */ + private int connectionMinimumIdleSize; + + /** + * 连接池大小 + */ + private int connectionPoolSize; + + /** + * 连接空闲超时,单位:毫秒 + */ + private int idleConnectionTimeout; + + /** + * 命令等待超时,单位:毫秒 + */ + private int timeout; + + /** + * 发布和订阅连接池大小 + */ + private int subscriptionConnectionPoolSize; + + } + + @Data + @NoArgsConstructor + public static class ClusterServersConfig { + + /** + * 客户端名称 + */ + private String clientName; + + /** + * master最小空闲连接数 + */ + private int masterConnectionMinimumIdleSize; + + /** + * master连接池大小 + */ + private int masterConnectionPoolSize; + + /** + * slave最小空闲连接数 + */ + private int slaveConnectionMinimumIdleSize; + + /** + * slave连接池大小 + */ + private int slaveConnectionPoolSize; + + /** + * 连接空闲超时,单位:毫秒 + */ + private int idleConnectionTimeout; + + /** + * 命令等待超时,单位:毫秒 + */ + private int timeout; + + /** + * 发布和订阅连接池大小 + */ + private int subscriptionConnectionPoolSize; + + /** + * 读取模式 + */ + private ReadMode readMode; + + /** + * 订阅模式 + */ + private SubscriptionMode subscriptionMode; + + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/KeyPrefixHandler.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/KeyPrefixHandler.java index ba9289eb4..f34ddc83a 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/KeyPrefixHandler.java +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/KeyPrefixHandler.java @@ -1,6 +1,5 @@ package org.dromara.common.redis.handler; -import org.apache.commons.lang3.Strings; import org.dromara.common.core.utils.StringUtils; import org.redisson.config.NameMapper; @@ -25,7 +24,10 @@ public class KeyPrefixHandler implements NameMapper { */ @Override public String map(String name) { - if (StringUtils.isNoneBlank(name,keyPrefix) && !Strings.CS.startsWith(name, keyPrefix)) { + if (StringUtils.isBlank(name)) { + return null; + } + if (StringUtils.isNotBlank(keyPrefix) && !name.startsWith(keyPrefix)) { return keyPrefix + name; } return name; @@ -36,7 +38,10 @@ public class KeyPrefixHandler implements NameMapper { */ @Override public String unmap(String name) { - if (StringUtils.isNoneBlank(name,keyPrefix) && Strings.CS.startsWith(name, keyPrefix)) { + if (StringUtils.isBlank(name)) { + return null; + } + if (StringUtils.isNotBlank(keyPrefix) && name.startsWith(keyPrefix)) { return name.substring(keyPrefix.length()); } return name;