From e7fe1afe1994574f5f0ec3ccb5506755a02044c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=9B=84?= Date: Tue, 21 Apr 2026 14:08:16 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A1=E3=80=81redis?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E3=80=81=E7=BB=9F=E4=B8=80=E4=BA=86=E6=89=80?= =?UTF-8?q?=E6=9C=89=E6=A8=A1=E5=BC=8F=EF=BC=88=E5=8D=95=E6=9C=BA=E3=80=81?= =?UTF-8?q?=E9=9B=86=E7=BE=A4=E3=80=81=E4=B8=BB=E4=BB=8E=E3=80=81=E5=93=A8?= =?UTF-8?q?=E5=85=B5=EF=BC=89=E7=9A=84=E9=85=8D=E7=BD=AE=E5=8F=82=E6=95=B0?= =?UTF-8?q?=EF=BC=9A=E9=83=BD=E8=AE=BE=E7=BD=AE=E4=BA=86=20retryAttempts,?= =?UTF-8?q?=20retryInterval,=20timeout,=20connectTimeout,=20idleConnection?= =?UTF-8?q?Timeout,=20=E8=BF=9E=E6=8E=A5=E6=B1=A0=E5=A4=A7=E5=B0=8F?= =?UTF-8?q?=E7=AD=89=E3=80=823=E3=80=81=E5=9C=B0=E5=9D=80=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=A1=A5=E9=BD=90=E5=8D=8F=E8=AE=AE=E5=89=8D=E7=BC=80?= =?UTF-8?q?=EF=BC=9AnormalizeAddress()=20=E6=96=B9=E6=B3=95=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=B7=BB=E5=8A=A0=20redis://=EF=BC=8C=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E9=85=8D=E7=BD=AE=E5=8F=AF=E4=BB=A5=E7=9C=81=E7=95=A5?= =?UTF-8?q?=EF=BC=8C=20=E5=85=B6=E4=BB=96=E7=AD=89=E7=AD=89=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/keking/config/RedissonConfig.java | 415 ++++++++---------- .../cache/impl/CacheServiceRedisImpl.java | 7 +- 2 files changed, 189 insertions(+), 233 deletions(-) diff --git a/server/src/main/java/cn/keking/config/RedissonConfig.java b/server/src/main/java/cn/keking/config/RedissonConfig.java index 5d824486..615d3a3e 100644 --- a/server/src/main/java/cn/keking/config/RedissonConfig.java +++ b/server/src/main/java/cn/keking/config/RedissonConfig.java @@ -1,6 +1,5 @@ package cn.keking.config; -import io.netty.channel.nio.NioEventLoopGroup; import org.apache.commons.lang3.StringUtils; import org.redisson.Redisson; import org.redisson.api.RedissonClient; @@ -13,8 +12,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.util.ClassUtils; /** - * Redisson 客户端配置 - * Created by kl on 2017/09/26. + * Redisson 客户端配置(完善版) + * 支持 single / cluster / master-slave / sentinel 四种模式,配置完整,统一参数。 */ @ConditionalOnExpression("'${cache.type:default}'.equals('redis')") @ConfigurationProperties(prefix = "spring.redisson") @@ -22,114 +21,71 @@ import org.springframework.util.ClassUtils; public class RedissonConfig { // ========================== 连接配置 ========================== - private static String address; - private static String password; - private static String clientName; - private static int database = 0; - private static String mode = "single"; - private static String masterName = "kkfile"; + private String address; + private String password; + private String clientName; + private int database = 0; + private String mode = "single"; + private String masterName = "kkfile"; // ========================== 超时配置 ========================== - private static int idleConnectionTimeout = 10000; - private static int connectTimeout = 10000; - private static int timeout = 3000; + private int idleConnectionTimeout = 10000; + private int connectTimeout = 10000; + private int timeout = 3000; // ========================== 重试配置 ========================== - private static int retryAttempts = 3; - private static int retryInterval = 1500; + private int retryAttempts = 3; + private int retryInterval = 1500; // ========================== 连接池配置 ========================== - private static int connectionMinimumIdleSize = 10; - private static int connectionPoolSize = 64; - private static int subscriptionsPerConnection = 5; - private static int subscriptionConnectionMinimumIdleSize = 1; - private static int subscriptionConnectionPoolSize = 50; + private int connectionMinimumIdleSize = 10; + private int connectionPoolSize = 64; + private int subscriptionsPerConnection = 5; + private int subscriptionConnectionMinimumIdleSize = 1; + private int subscriptionConnectionPoolSize = 50; + + // ========================== 集群专用配置 ========================== + private int scanInterval = 2000; // ========================== 其他配置 ========================== - private static int dnsMonitoringInterval = 5000; - private static int thread; // 当前处理核数量 * 2 - private static String codec = "org.redisson.codec.JsonJacksonCodec"; + private int dnsMonitoringInterval = 5000; + private int threads; // 默认为0,表示使用 CPU 核数 * 2 + private String codec = "org.redisson.codec.JsonJacksonCodec"; @Bean - public static RedissonClient config() throws Exception { + public RedissonClient redissonClient() { Config config = new Config(); - // 密码处理 - if (StringUtils.isBlank(password)) { - password = null; - } + // 密码处理:空字符串转为 null + String pwd = StringUtils.isBlank(password) ? null : password; - // 根据模式创建对应的 Redisson 配置 - switch (mode) { + // 根据模式构建配置 + switch (mode.toLowerCase()) { case "cluster": - configureClusterMode(config); + configureClusterMode(config, pwd); break; case "master-slave": - configureMasterSlaveMode(config); + configureMasterSlaveMode(config, pwd); break; case "sentinel": - configureSentinelMode(config); + configureSentinelMode(config, pwd); break; default: - configureSingleMode(config); + configureSingleMode(config, pwd); break; } + // 公共配置:编码器、线程数 + applyCommonConfig(config); return Redisson.create(config); } // ========================== 配置方法 ========================== - /** - * 配置集群模式 - */ - private static void configureClusterMode(Config config) { - String[] clusterAddresses = address.split(","); - config.useClusterServers() - .setScanInterval(2000) - .addNodeAddress(clusterAddresses) - .setPassword(password) - .setRetryAttempts(retryAttempts) - .setTimeout(timeout) - .setMasterConnectionPoolSize(100) - .setSlaveConnectionPoolSize(100); - } - - /** - * 配置主从模式 - */ - private static void configureMasterSlaveMode(Config config) { - String[] masterSlaveAddresses = address.split(","); - validateMasterSlaveAddresses(masterSlaveAddresses); - - String[] slaveAddresses = new String[masterSlaveAddresses.length - 1]; - System.arraycopy(masterSlaveAddresses, 1, slaveAddresses, 0, slaveAddresses.length); - - config.useMasterSlaveServers() - .setDatabase(database) - .setPassword(password) - .setMasterAddress(masterSlaveAddresses[0]) - .addSlaveAddress(slaveAddresses); - } - - /** - * 配置哨兵模式 - */ - private static void configureSentinelMode(Config config) { - String[] sentinelAddresses = address.split(","); - config.useSentinelServers() - .setDatabase(database) - .setPassword(password) - .setMasterName(masterName) - .addSentinelAddress(sentinelAddresses); - } - - /** - * 配置单机模式 - */ - private static void configureSingleMode(Config config) throws Exception { + private void configureSingleMode(Config config, String pwd) { + String normalizedAddress = normalizeAddress(address); config.useSingleServer() - .setAddress(address) + .setAddress(normalizedAddress) .setConnectionMinimumIdleSize(connectionMinimumIdleSize) .setConnectionPoolSize(connectionPoolSize) .setDatabase(database) @@ -143,183 +99,184 @@ public class RedissonConfig { .setTimeout(timeout) .setConnectTimeout(connectTimeout) .setIdleConnectionTimeout(idleConnectionTimeout) - .setPassword(StringUtils.trimToNull(password)); - - // 设置编码器 - Class codecClass = ClassUtils.forName(getCodec(), ClassUtils.getDefaultClassLoader()); - Codec codecInstance = (Codec) codecClass.getDeclaredConstructor().newInstance(); - config.setCodec(codecInstance); - // 设置线程和事件循环组 - config.setThreads(thread); - config.setEventLoopGroup(new NioEventLoopGroup()); + .setPassword(pwd); } - /** - * 验证主从模式地址 - */ - private static void validateMasterSlaveAddresses(String[] addresses) { - if (addresses.length == 1) { - throw new IllegalArgumentException( - "redis.redisson.address MUST have multiple redis addresses for master-slave mode."); + private void configureClusterMode(Config config, String pwd) { + String[] nodeAddresses = normalizeAddresses(address.split(",")); + config.useClusterServers() + .setScanInterval(scanInterval) + .addNodeAddress(nodeAddresses) + .setPassword(pwd) + .setRetryAttempts(retryAttempts) + .setRetryInterval(retryInterval) + .setTimeout(timeout) + .setConnectTimeout(connectTimeout) + .setIdleConnectionTimeout(idleConnectionTimeout) + .setMasterConnectionPoolSize(connectionPoolSize) + .setSlaveConnectionPoolSize(connectionPoolSize) + .setSubscriptionConnectionPoolSize(subscriptionConnectionPoolSize) + .setSubscriptionConnectionMinimumIdleSize(subscriptionConnectionMinimumIdleSize) + .setSubscriptionsPerConnection(subscriptionsPerConnection) + .setClientName(clientName); + } + + private void configureMasterSlaveMode(Config config, String pwd) { + String[] addresses = address.split(","); + validateMasterSlaveAddresses(addresses); + String[] normalizedAddresses = normalizeAddresses(addresses); + String masterAddress = normalizedAddresses[0]; + String[] slaveAddresses = new String[normalizedAddresses.length - 1]; + System.arraycopy(normalizedAddresses, 1, slaveAddresses, 0, slaveAddresses.length); + + config.useMasterSlaveServers() + .setDatabase(database) + .setPassword(pwd) + .setMasterAddress(masterAddress) + .addSlaveAddress(slaveAddresses) + .setRetryAttempts(retryAttempts) + .setRetryInterval(retryInterval) + .setTimeout(timeout) + .setConnectTimeout(connectTimeout) + .setIdleConnectionTimeout(idleConnectionTimeout) + .setMasterConnectionPoolSize(connectionPoolSize) + .setSlaveConnectionPoolSize(connectionPoolSize) + .setSubscriptionConnectionPoolSize(subscriptionConnectionPoolSize) + .setSubscriptionConnectionMinimumIdleSize(subscriptionConnectionMinimumIdleSize) + .setSubscriptionsPerConnection(subscriptionsPerConnection) + .setClientName(clientName); + } + + private void configureSentinelMode(Config config, String pwd) { + String[] sentinelAddresses = normalizeAddresses(address.split(",")); + config.useSentinelServers() + .setDatabase(database) + .setPassword(pwd) + .setMasterName(masterName) + .addSentinelAddress(sentinelAddresses) + .setRetryAttempts(retryAttempts) + .setRetryInterval(retryInterval) + .setTimeout(timeout) + .setConnectTimeout(connectTimeout) + .setIdleConnectionTimeout(idleConnectionTimeout) + .setMasterConnectionPoolSize(connectionPoolSize) + .setSlaveConnectionPoolSize(connectionPoolSize) + .setSubscriptionConnectionPoolSize(subscriptionConnectionPoolSize) + .setSubscriptionConnectionMinimumIdleSize(subscriptionConnectionMinimumIdleSize) + .setSubscriptionsPerConnection(subscriptionsPerConnection) + .setClientName(clientName); + } + + private void applyCommonConfig(Config config) { + // 设置编码器 + if (StringUtils.isNotBlank(codec)) { + try { + Class codecClass = ClassUtils.forName(codec, ClassUtils.getDefaultClassLoader()); + Codec codecInstance = (Codec) codecClass.getDeclaredConstructor().newInstance(); + config.setCodec(codecInstance); + } catch (Exception e) { + throw new IllegalStateException("Failed to create Redisson codec: " + codec, e); + } + } + // 设置线程数(大于0时生效,否则Redisson使用默认值:CPU核数*2) + if (threads > 0) { + config.setThreads(threads); } } - // ========================== Getter和Setter方法 ========================== + // ========================== 辅助方法 ========================== - // 连接配置 - public String getAddress() { - return address; + /** + * 自动补齐 Redis 地址协议前缀(redis:// 或 rediss://) + */ + private String normalizeAddress(String addr) { + if (addr == null) { + return null; + } + addr = addr.trim(); + if (!addr.startsWith("redis://") && !addr.startsWith("rediss://")) { + addr = "redis://" + addr; + } + return addr; } - public void setAddress(String address) { - RedissonConfig.address = address; + private String[] normalizeAddresses(String[] addresses) { + String[] normalized = new String[addresses.length]; + for (int i = 0; i < addresses.length; i++) { + normalized[i] = normalizeAddress(addresses[i]); + } + return normalized; } - public String getPassword() { - return password; + private void validateMasterSlaveAddresses(String[] addresses) { + if (addresses.length < 2) { + throw new IllegalArgumentException( + "Master-slave mode requires at least 2 addresses: master and at least one slave. " + + "Current addresses: " + String.join(",", addresses)); + } } - public void setPassword(String password) { - RedissonConfig.password = password; - } + // ========================== Getter / Setter(供 Spring 绑定配置) ========================== + // 以下所有字段都需要提供 getter/setter,示例中只列出关键字段,实际使用时请补全所有字段。 + // 建议使用 Lombok @Data 或 IDE 自动生成。这里只展示部分,避免篇幅过长。 - public String getClientName() { - return clientName; - } + public String getAddress() { return address; } + public void setAddress(String address) { this.address = address; } - public void setClientName(String clientName) { - RedissonConfig.clientName = clientName; - } + public String getPassword() { return password; } + public void setPassword(String password) { this.password = password; } - public int getDatabase() { - return database; - } + public String getClientName() { return clientName; } + public void setClientName(String clientName) { this.clientName = clientName; } - public void setDatabase(int database) { - RedissonConfig.database = database; - } + public int getDatabase() { return database; } + public void setDatabase(int database) { this.database = database; } - public static String getMode() { - return mode; - } + public String getMode() { return mode; } + public void setMode(String mode) { this.mode = mode; } - public void setMode(String mode) { - RedissonConfig.mode = mode; - } + public String getMasterName() { return masterName; } + public void setMasterName(String masterName) { this.masterName = masterName; } - public static String getMasterNamee() { - return masterName; - } + public int getIdleConnectionTimeout() { return idleConnectionTimeout; } + public void setIdleConnectionTimeout(int idleConnectionTimeout) { this.idleConnectionTimeout = idleConnectionTimeout; } - public void setMasterNamee(String masterName) { - RedissonConfig.masterName = masterName; - } + public int getConnectTimeout() { return connectTimeout; } + public void setConnectTimeout(int connectTimeout) { this.connectTimeout = connectTimeout; } - // 超时配置 - public int getIdleConnectionTimeout() { - return idleConnectionTimeout; - } + public int getTimeout() { return timeout; } + public void setTimeout(int timeout) { this.timeout = timeout; } - public void setIdleConnectionTimeout(int idleConnectionTimeout) { - RedissonConfig.idleConnectionTimeout = idleConnectionTimeout; - } + public int getRetryAttempts() { return retryAttempts; } + public void setRetryAttempts(int retryAttempts) { this.retryAttempts = retryAttempts; } - public int getConnectTimeout() { - return connectTimeout; - } + public int getRetryInterval() { return retryInterval; } + public void setRetryInterval(int retryInterval) { this.retryInterval = retryInterval; } - public void setConnectTimeout(int connectTimeout) { - RedissonConfig.connectTimeout = connectTimeout; - } + public int getConnectionMinimumIdleSize() { return connectionMinimumIdleSize; } + public void setConnectionMinimumIdleSize(int connectionMinimumIdleSize) { this.connectionMinimumIdleSize = connectionMinimumIdleSize; } - public int getTimeout() { - return timeout; - } + public int getConnectionPoolSize() { return connectionPoolSize; } + public void setConnectionPoolSize(int connectionPoolSize) { this.connectionPoolSize = connectionPoolSize; } - public void setTimeout(int timeout) { - RedissonConfig.timeout = timeout; - } + public int getSubscriptionsPerConnection() { return subscriptionsPerConnection; } + public void setSubscriptionsPerConnection(int subscriptionsPerConnection) { this.subscriptionsPerConnection = subscriptionsPerConnection; } - // 重试配置 - public int getRetryAttempts() { - return retryAttempts; - } + public int getSubscriptionConnectionMinimumIdleSize() { return subscriptionConnectionMinimumIdleSize; } + public void setSubscriptionConnectionMinimumIdleSize(int subscriptionConnectionMinimumIdleSize) { this.subscriptionConnectionMinimumIdleSize = subscriptionConnectionMinimumIdleSize; } - public void setRetryAttempts(int retryAttempts) { - RedissonConfig.retryAttempts = retryAttempts; - } + public int getSubscriptionConnectionPoolSize() { return subscriptionConnectionPoolSize; } + public void setSubscriptionConnectionPoolSize(int subscriptionConnectionPoolSize) { this.subscriptionConnectionPoolSize = subscriptionConnectionPoolSize; } - public int getRetryInterval() { - return retryInterval; - } + public int getScanInterval() { return scanInterval; } + public void setScanInterval(int scanInterval) { this.scanInterval = scanInterval; } - public void setRetryInterval(int retryInterval) { - RedissonConfig.retryInterval = retryInterval; - } + public int getDnsMonitoringInterval() { return dnsMonitoringInterval; } + public void setDnsMonitoringInterval(int dnsMonitoringInterval) { this.dnsMonitoringInterval = dnsMonitoringInterval; } - // 连接池配置 - public int getConnectionMinimumIdleSize() { - return connectionMinimumIdleSize; - } + public int getThreads() { return threads; } + public void setThreads(int threads) { this.threads = threads; } - public void setConnectionMinimumIdleSize(int connectionMinimumIdleSize) { - RedissonConfig.connectionMinimumIdleSize = connectionMinimumIdleSize; - } - - public int getConnectionPoolSize() { - return connectionPoolSize; - } - - public void setConnectionPoolSize(int connectionPoolSize) { - RedissonConfig.connectionPoolSize = connectionPoolSize; - } - - public int getSubscriptionsPerConnection() { - return subscriptionsPerConnection; - } - - public void setSubscriptionsPerConnection(int subscriptionsPerConnection) { - RedissonConfig.subscriptionsPerConnection = subscriptionsPerConnection; - } - - public int getSubscriptionConnectionMinimumIdleSize() { - return subscriptionConnectionMinimumIdleSize; - } - - public void setSubscriptionConnectionMinimumIdleSize(int subscriptionConnectionMinimumIdleSize) { - RedissonConfig.subscriptionConnectionMinimumIdleSize = subscriptionConnectionMinimumIdleSize; - } - - public int getSubscriptionConnectionPoolSize() { - return subscriptionConnectionPoolSize; - } - - public void setSubscriptionConnectionPoolSize(int subscriptionConnectionPoolSize) { - RedissonConfig.subscriptionConnectionPoolSize = subscriptionConnectionPoolSize; - } - - // 其他配置 - public int getDnsMonitoringInterval() { - return dnsMonitoringInterval; - } - - public void setDnsMonitoringInterval(int dnsMonitoringInterval) { - RedissonConfig.dnsMonitoringInterval = dnsMonitoringInterval; - } - - public int getThread() { - return thread; - } - - public void setThread(int thread) { - RedissonConfig.thread = thread; - } - - public static String getCodec() { - return codec; - } - - public void setCodec(String codec) { - RedissonConfig.codec = codec; - } + public String getCodec() { return codec; } + public void setCodec(String codec) { this.codec = codec; } } \ No newline at end of file diff --git a/server/src/main/java/cn/keking/service/cache/impl/CacheServiceRedisImpl.java b/server/src/main/java/cn/keking/service/cache/impl/CacheServiceRedisImpl.java index b7cb971a..6ead0ef8 100644 --- a/server/src/main/java/cn/keking/service/cache/impl/CacheServiceRedisImpl.java +++ b/server/src/main/java/cn/keking/service/cache/impl/CacheServiceRedisImpl.java @@ -1,11 +1,9 @@ package cn.keking.service.cache.impl; import cn.keking.service.cache.CacheService; -import org.redisson.Redisson; import org.redisson.api.RBlockingQueue; import org.redisson.api.RMapCache; import org.redisson.api.RedissonClient; -import org.redisson.config.Config; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; @@ -23,8 +21,9 @@ public class CacheServiceRedisImpl implements CacheService { private final RedissonClient redissonClient; - public CacheServiceRedisImpl(Config config) { - this.redissonClient = Redisson.create(config); + // 直接注入 Spring 容器中的 RedissonClient Bean + public CacheServiceRedisImpl(RedissonClient redissonClient) { + this.redissonClient = redissonClient; } @Override