first commit

This commit is contained in:
2026-01-30 14:25:12 +08:00
commit 8dd8d2668a
899 changed files with 90844 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.qingyun</groupId>
<artifactId>qingyun-framework</artifactId>
<version>4.7.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>qingyun-redis</artifactId>
<description>redis配置</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.qingyun</groupId>
<artifactId>qingyun-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,130 @@
package com.qingyun.redis.config;
import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qingyun.redis.handler.KeyPrefixHandler;
import com.qingyun.redis.manager.PlusSpringCacheManager;
import com.qingyun.redis.properties.RedissonProperties;
import lombok.extern.slf4j.Slf4j;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* redis配置
*
* @author jianlu
*/
@Slf4j
@Configuration
@EnableCaching
@EnableConfigurationProperties(RedissonProperties.class)
public class RedisConfig {
@Autowired
private RedissonProperties redissonProperties;
@Autowired
private ObjectMapper objectMapper;
@Bean
public RedissonAutoConfigurationCustomizer redissonCustomizer() {
return config -> {
config.setThreads(redissonProperties.getThreads())
.setNettyThreads(redissonProperties.getNettyThreads())
.setCodec(new JsonJacksonCodec(objectMapper));
RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
if (ObjectUtil.isNotNull(singleServerConfig)) {
// 使用单机模式
config.useSingleServer()
//设置redis key前缀
.setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()))
.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()
//设置redis key前缀
.setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()))
.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 配置");
};
}
/**
* 自定义缓存管理器 整合spring-cache
*/
@Bean
public CacheManager cacheManager() {
return new PlusSpringCacheManager();
}
/**
* redis集群配置 yml
*
* --- # redis 集群配置(单机与集群只能开启一个另一个需要注释掉)
* spring:
* redis:
* cluster:
* nodes:
* - 192.168.0.100:6379
* - 192.168.0.101:6379
* - 192.168.0.102:6379
* # 密码
* password:
* # 连接超时时间
* timeout: 10s
* # 是否开启ssl
* ssl: 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"
*/
}

View File

@@ -0,0 +1,50 @@
package com.qingyun.redis.handler;
import com.qingyun.common.utils.StringUtils;
import org.redisson.api.NameMapper;
/**
* redis缓存key前缀处理
*
* @author ye
* @date 2022/7/14 17:44
* @since 4.3.0
*/
public class KeyPrefixHandler implements NameMapper {
private final String keyPrefix;
public KeyPrefixHandler(String keyPrefix) {
//前缀为空 则返回空前缀
this.keyPrefix = StringUtils.isBlank(keyPrefix) ? "" : keyPrefix + ":";
}
/**
* 增加前缀
*/
@Override
public String map(String name) {
if (StringUtils.isBlank(name)) {
return null;
}
if (StringUtils.isNotBlank(keyPrefix) && !name.startsWith(keyPrefix)) {
return keyPrefix + name;
}
return name;
}
/**
* 去除前缀
*/
@Override
public String unmap(String name) {
if (StringUtils.isBlank(name)) {
return null;
}
if (StringUtils.isNotBlank(keyPrefix) && name.startsWith(keyPrefix)) {
return name.substring(keyPrefix.length());
}
return name;
}
}

View File

@@ -0,0 +1,191 @@
/**
* Copyright (c) 2013-2021 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qingyun.redis.manager;
import com.qingyun.common.utils.redis.RedisUtils;
import org.redisson.api.RMap;
import org.redisson.api.RMapCache;
import org.redisson.spring.cache.CacheConfig;
import org.redisson.spring.cache.RedissonCache;
import org.springframework.boot.convert.DurationStyle;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.transaction.TransactionAwareCacheDecorator;
import org.springframework.util.StringUtils;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* A {@link org.springframework.cache.CacheManager} implementation
* backed by Redisson instance.
* <p>
* 修改 RedissonSpringCacheManager 源码
* 重写 cacheName 处理方法 支持多参数
*
* @author Nikita Koksharov
*
*/
@SuppressWarnings("unchecked")
public class PlusSpringCacheManager implements CacheManager {
private boolean dynamic = true;
private boolean allowNullValues = true;
private boolean transactionAware = true;
Map<String, CacheConfig> configMap = new ConcurrentHashMap<>();
ConcurrentMap<String, Cache> instanceMap = new ConcurrentHashMap<>();
/**
* Creates CacheManager supplied by Redisson instance
*/
public PlusSpringCacheManager() {
}
/**
* Defines possibility of storing {@code null} values.
* <p>
* Default is <code>true</code>
*
* @param allowNullValues stores if <code>true</code>
*/
public void setAllowNullValues(boolean allowNullValues) {
this.allowNullValues = allowNullValues;
}
/**
* Defines if cache aware of Spring-managed transactions.
* If {@code true} put/evict operations are executed only for successful transaction in after-commit phase.
* <p>
* Default is <code>false</code>
*
* @param transactionAware cache is transaction aware if <code>true</code>
*/
public void setTransactionAware(boolean transactionAware) {
this.transactionAware = transactionAware;
}
/**
* Defines 'fixed' cache names.
* A new cache instance will not be created in dynamic for non-defined names.
* <p>
* `null` parameter setups dynamic mode
*
* @param names of caches
*/
public void setCacheNames(Collection<String> names) {
if (names != null) {
for (String name : names) {
getCache(name);
}
dynamic = false;
} else {
dynamic = true;
}
}
/**
* Set cache config mapped by cache name
*
* @param config object
*/
public void setConfig(Map<String, ? extends CacheConfig> config) {
this.configMap = (Map<String, CacheConfig>) config;
}
protected CacheConfig createDefaultConfig() {
return new CacheConfig();
}
@Override
public Cache getCache(String name) {
Cache cache = instanceMap.get(name);
if (cache != null) {
return cache;
}
if (!dynamic) {
return cache;
}
CacheConfig config = configMap.get(name);
if (config == null) {
config = createDefaultConfig();
configMap.put(name, config);
}
// 重写 cacheName 支持多参数
String[] array = StringUtils.delimitedListToStringArray(name, "#");
name = array[0];
if (array.length > 1) {
config.setTTL(DurationStyle.detectAndParse(array[1]).toMillis());
}
if (array.length > 2) {
config.setMaxIdleTime(DurationStyle.detectAndParse(array[2]).toMillis());
}
if (array.length > 3) {
config.setMaxSize(Integer.parseInt(array[3]));
}
if (config.getMaxIdleTime() == 0 && config.getTTL() == 0 && config.getMaxSize() == 0) {
return createMap(name, config);
}
return createMapCache(name, config);
}
private Cache createMap(String name, CacheConfig config) {
RMap<Object, Object> map = RedisUtils.getClient().getMap(name);
Cache cache = new RedissonCache(map, allowNullValues);
if (transactionAware) {
cache = new TransactionAwareCacheDecorator(cache);
}
Cache oldCache = instanceMap.putIfAbsent(name, cache);
if (oldCache != null) {
cache = oldCache;
}
return cache;
}
private Cache createMapCache(String name, CacheConfig config) {
RMapCache<Object, Object> map = RedisUtils.getClient().getMapCache(name);
Cache cache = new RedissonCache(map, config, allowNullValues);
if (transactionAware) {
cache = new TransactionAwareCacheDecorator(cache);
}
Cache oldCache = instanceMap.putIfAbsent(name, cache);
if (oldCache != null) {
cache = oldCache;
} else {
map.setMaxSize(config.getMaxSize());
}
return cache;
}
@Override
public Collection<String> getCacheNames() {
return Collections.unmodifiableSet(configMap.keySet());
}
}

View File

@@ -0,0 +1,137 @@
package com.qingyun.redis.properties;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.redisson.config.ReadMode;
import org.redisson.config.SubscriptionMode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* Redisson 配置属性
*
* @author jianlu
*/
@Data
@Component
@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;
}
}