From 7c3a5c4a1d6dfe639b2adb7352f24b3e97fbb70a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E8=BE=9E=E6=9C=AA=E5=AF=92?= <545073804@qq.com> Date: Thu, 29 Jan 2026 17:13:19 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E4=BD=BF=E7=94=A8Spring=20Redis=20Dat?= =?UTF-8?q?a=E8=87=AA=E5=8A=A8=E9=85=8D=E7=BD=AE=E9=A1=B9=E4=BC=98?= =?UTF-8?q?=E5=8C=96Redisson=204.X=E9=85=8D=E7=BD=AE=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit update 优化Redisson自定义配置,Json序列化依赖升级至Jackson3.X --- .../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, 110 insertions(+), 278 deletions(-) delete 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 1b52fab96..7768f4afd 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -107,29 +107,28 @@ spring.data: timeout: 10s # 是否开启ssl ssl.enabled: false - -# 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 + # 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 --- # mail 邮件发送 mail: diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml index d77ddf57c..6fc718f05 100644 --- a/ruoyi-admin/src/main/resources/application-prod.yml +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -110,29 +110,28 @@ spring.data: timeout: 10s # 是否开启ssl ssl.enabled: false - -# 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 + # 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 --- # mail 邮件发送 mail: diff --git a/ruoyi-common/ruoyi-common-redis/pom.xml b/ruoyi-common/ruoyi-common-redis/pom.xml index 12cb577f7..b42603fa1 100644 --- a/ruoyi-common/ruoyi-common-redis/pom.xml +++ b/ruoyi-common/ruoyi-common-redis/pom.xml @@ -45,8 +45,8 @@ - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 + tools.jackson.core + jackson-databind 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 2e82330f2..a11333ac4 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,28 +1,25 @@ 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.TypedJsonJacksonCodec; +import org.redisson.codec.TypedJsonJackson3Codec; import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; 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; @@ -35,68 +32,45 @@ import java.util.TimeZone; */ @Slf4j @AutoConfiguration -@EnableConfigurationProperties(RedissonProperties.class) public class RedisConfig { - @Autowired - private RedissonProperties redissonProperties; - + /** + * 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() { + public RedissonAutoConfigurationCustomizer redissonCustomizer(@Value("${spring.data.redis.redisson.keyPrefix}") String keyPrefix) { + return config -> { - JavaTimeModule javaTimeModule = new JavaTimeModule(); + SimpleModule simpleModule = new SimpleModule(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - 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); + 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(); // org.apache.fory.logging.LoggerFactory 包别引入错了 // LoggerFactory.useSlf4jLogging(true); // ForyCodec foryCodec = new ForyCodec(); // CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, foryCodec, foryCodec); - TypedJsonJacksonCodec jsonCodec = new TypedJsonJacksonCodec(Object.class, om); + TypedJsonJackson3Codec jsonCodec = new TypedJsonJackson3Codec(Object.class, jsonMapper); // 组合序列化 key 使用 String 内容使用通用 json 格式 CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, jsonCodec, jsonCodec); - config.setThreads(redissonProperties.getThreads()) - .setNettyThreads(redissonProperties.getNettyThreads()) - // 缓存 Lua 脚本 减少网络传输(redisson 大部分的功能都是基于 Lua 脚本实现) - .setUseScriptCache(true) - //设置redis key前缀 - .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) - .setCodec(codec); + config.setCodec(codec); if (SpringUtils.isVirtual()) { config.setNettyExecutor(new VirtualThreadTaskExecutor("redisson-")); } - 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()); - } + config.setNameMapper(new KeyPrefixHandler(keyPrefix)); log.info("初始化 redis 配置"); }; } @@ -126,34 +100,34 @@ public class RedisConfig { * timeout: 10s * # 是否开启ssl * ssl.enabled: false - * - * 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配置 + * 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 deleted file mode 100644 index ebec7861a..000000000 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java +++ /dev/null @@ -1,135 +0,0 @@ -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 f34ddc83a..ba9289eb4 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,5 +1,6 @@ package org.dromara.common.redis.handler; +import org.apache.commons.lang3.Strings; import org.dromara.common.core.utils.StringUtils; import org.redisson.config.NameMapper; @@ -24,10 +25,7 @@ public class KeyPrefixHandler implements NameMapper { */ @Override public String map(String name) { - if (StringUtils.isBlank(name)) { - return null; - } - if (StringUtils.isNotBlank(keyPrefix) && !name.startsWith(keyPrefix)) { + if (StringUtils.isNoneBlank(name,keyPrefix) && !Strings.CS.startsWith(name, keyPrefix)) { return keyPrefix + name; } return name; @@ -38,10 +36,7 @@ public class KeyPrefixHandler implements NameMapper { */ @Override public String unmap(String name) { - if (StringUtils.isBlank(name)) { - return null; - } - if (StringUtils.isNotBlank(keyPrefix) && name.startsWith(keyPrefix)) { + if (StringUtils.isNoneBlank(name,keyPrefix) && Strings.CS.startsWith(name, keyPrefix)) { return name.substring(keyPrefix.length()); } return name;