first commit
This commit is contained in:
26
qingyun-framework/qingyun-redis/pom.xml
Normal file
26
qingyun-framework/qingyun-redis/pom.xml
Normal 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>
|
||||
@@ -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"
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user