update 重写 spring-cache 实现 更人性化的操作 支持注解指定ttl等一些参数
This commit is contained in:
parent
5d367b7bf8
commit
89c1e4f91d
@ -233,21 +233,6 @@ thread-pool:
|
|||||||
# 线程池维护线程所允许的空闲时间
|
# 线程池维护线程所允许的空闲时间
|
||||||
keepAliveSeconds: 300
|
keepAliveSeconds: 300
|
||||||
|
|
||||||
--- # redisson 缓存配置
|
|
||||||
redisson:
|
|
||||||
cacheGroup:
|
|
||||||
# 用例: @Cacheable(cacheNames="groupId", key="#XXX") 方可使用缓存组配置
|
|
||||||
- groupId: redissonCacheMap
|
|
||||||
# 组过期时间(脚本监控)
|
|
||||||
ttl: 60000
|
|
||||||
# 组最大空闲时间(脚本监控)
|
|
||||||
maxIdleTime: 60000
|
|
||||||
# 组最大长度
|
|
||||||
maxSize: 0
|
|
||||||
- groupId: testCache
|
|
||||||
ttl: 1000
|
|
||||||
maxIdleTime: 500
|
|
||||||
|
|
||||||
--- # 分布式锁 lock4j 全局配置
|
--- # 分布式锁 lock4j 全局配置
|
||||||
lock4j:
|
lock4j:
|
||||||
# 获取分布式锁超时时间,默认为 3000 毫秒
|
# 获取分布式锁超时时间,默认为 3000 毫秒
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.ruoyi.common.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存组名称常量
|
||||||
|
* <p>
|
||||||
|
* key 格式为 cacheNames#ttl#maxIdleTime#maxSize
|
||||||
|
* <p>
|
||||||
|
* ttl 过期时间 如果设置为0则不过期 默认为0
|
||||||
|
* maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0
|
||||||
|
* maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0
|
||||||
|
* <p>
|
||||||
|
* 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
public interface CacheNames {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 演示案例
|
||||||
|
*/
|
||||||
|
String DEMO_CACHE = "demo:cache#60s#10m#20";
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package com.ruoyi.demo.controller;
|
package com.ruoyi.demo.controller;
|
||||||
|
|
||||||
|
import com.ruoyi.common.constant.CacheNames;
|
||||||
import com.ruoyi.common.core.domain.R;
|
import com.ruoyi.common.core.domain.R;
|
||||||
import com.ruoyi.common.utils.redis.RedisUtils;
|
import com.ruoyi.common.utils.redis.RedisUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -18,7 +19,7 @@ import java.time.Duration;
|
|||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
// 类级别 缓存统一配置
|
// 类级别 缓存统一配置
|
||||||
//@CacheConfig(cacheNames = "redissonCacheMap")
|
//@CacheConfig(cacheNames = CacheNames.DEMO_CACHE)
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/demo/cache")
|
@RequestMapping("/demo/cache")
|
||||||
@ -36,9 +37,9 @@ public class RedisCacheController {
|
|||||||
* 重点说明: 缓存注解严谨与其他筛选数据功能一起使用
|
* 重点说明: 缓存注解严谨与其他筛选数据功能一起使用
|
||||||
* 例如: 数据权限注解 会造成 缓存击穿 与 数据不一致问题
|
* 例如: 数据权限注解 会造成 缓存击穿 与 数据不一致问题
|
||||||
* <p>
|
* <p>
|
||||||
* cacheNames 为配置文件内 groupId
|
* cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数
|
||||||
*/
|
*/
|
||||||
@Cacheable(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
|
@Cacheable(cacheNames = "demo:cache#60s#10m#20", key = "#key", condition = "#key != null")
|
||||||
@GetMapping("/test1")
|
@GetMapping("/test1")
|
||||||
public R<String> test1(String key, String value) {
|
public R<String> test1(String key, String value) {
|
||||||
return R.ok("操作成功", value);
|
return R.ok("操作成功", value);
|
||||||
@ -48,11 +49,11 @@ public class RedisCacheController {
|
|||||||
* 测试 @CachePut
|
* 测试 @CachePut
|
||||||
* <p>
|
* <p>
|
||||||
* 加了@CachePut注解的方法,会把方法的返回值put到缓存里面缓存起来,供其它地方使用
|
* 加了@CachePut注解的方法,会把方法的返回值put到缓存里面缓存起来,供其它地方使用
|
||||||
* 它「通常用在新增方法上」
|
* 它「通常用在新增或者实时更新方法上」
|
||||||
* <p>
|
* <p>
|
||||||
* cacheNames 为 配置文件内 groupId
|
* cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数
|
||||||
*/
|
*/
|
||||||
@CachePut(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
|
@CachePut(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null")
|
||||||
@GetMapping("/test2")
|
@GetMapping("/test2")
|
||||||
public R<String> test2(String key, String value) {
|
public R<String> test2(String key, String value) {
|
||||||
return R.ok("操作成功", value);
|
return R.ok("操作成功", value);
|
||||||
@ -62,11 +63,11 @@ public class RedisCacheController {
|
|||||||
* 测试 @CacheEvict
|
* 测试 @CacheEvict
|
||||||
* <p>
|
* <p>
|
||||||
* 使用了CacheEvict注解的方法,会清空指定缓存
|
* 使用了CacheEvict注解的方法,会清空指定缓存
|
||||||
* 「一般用在更新或者删除的方法上」
|
* 「一般用在删除的方法上」
|
||||||
* <p>
|
* <p>
|
||||||
* cacheNames 为 配置文件内 groupId
|
* cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数
|
||||||
*/
|
*/
|
||||||
@CacheEvict(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
|
@CacheEvict(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null")
|
||||||
@GetMapping("/test3")
|
@GetMapping("/test3")
|
||||||
public R<String> test3(String key, String value) {
|
public R<String> test3(String key, String value) {
|
||||||
return R.ok("操作成功", value);
|
return R.ok("操作成功", value);
|
||||||
|
@ -4,11 +4,9 @@ import cn.hutool.core.util.ObjectUtil;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.ruoyi.framework.config.properties.RedissonProperties;
|
import com.ruoyi.framework.config.properties.RedissonProperties;
|
||||||
import com.ruoyi.framework.handler.KeyPrefixHandler;
|
import com.ruoyi.framework.handler.KeyPrefixHandler;
|
||||||
|
import com.ruoyi.framework.manager.PlusSpringCacheManager;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.redisson.api.RedissonClient;
|
|
||||||
import org.redisson.codec.JsonJacksonCodec;
|
import org.redisson.codec.JsonJacksonCodec;
|
||||||
import org.redisson.spring.cache.CacheConfig;
|
|
||||||
import org.redisson.spring.cache.RedissonSpringCacheManager;
|
|
||||||
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
|
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
@ -18,10 +16,6 @@ import org.springframework.cache.annotation.EnableCaching;
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* redis配置
|
* redis配置
|
||||||
*
|
*
|
||||||
@ -80,18 +74,11 @@ public class RedisConfig extends CachingConfigurerSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 整合spring-cache
|
* 自定义缓存管理器 整合spring-cache
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public CacheManager cacheManager(RedissonClient redissonClient) {
|
public CacheManager cacheManager() {
|
||||||
List<RedissonProperties.CacheGroup> cacheGroup = redissonProperties.getCacheGroup();
|
return new PlusSpringCacheManager();
|
||||||
Map<String, CacheConfig> config = new HashMap<>();
|
|
||||||
for (RedissonProperties.CacheGroup group : cacheGroup) {
|
|
||||||
CacheConfig cacheConfig = new CacheConfig(group.getTtl(), group.getMaxIdleTime());
|
|
||||||
cacheConfig.setMaxSize(group.getMaxSize());
|
|
||||||
config.put(group.getGroupId(), cacheConfig);
|
|
||||||
}
|
|
||||||
return new RedissonSpringCacheManager(redissonClient, config, new JsonJacksonCodec(objectMapper));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,8 +7,6 @@ import org.redisson.config.SubscriptionMode;
|
|||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redisson 配置属性
|
* Redisson 配置属性
|
||||||
*
|
*
|
||||||
@ -18,12 +16,12 @@ import java.util.List;
|
|||||||
@Component
|
@Component
|
||||||
@ConfigurationProperties(prefix = "redisson")
|
@ConfigurationProperties(prefix = "redisson")
|
||||||
public class RedissonProperties {
|
public class RedissonProperties {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* redis缓存key前缀
|
* redis缓存key前缀
|
||||||
*/
|
*/
|
||||||
private String keyPrefix;
|
private String keyPrefix;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 线程池数量,默认值 = 当前处理核数量 * 2
|
* 线程池数量,默认值 = 当前处理核数量 * 2
|
||||||
*/
|
*/
|
||||||
@ -44,11 +42,6 @@ public class RedissonProperties {
|
|||||||
*/
|
*/
|
||||||
private ClusterServersConfig clusterServersConfig;
|
private ClusterServersConfig clusterServersConfig;
|
||||||
|
|
||||||
/**
|
|
||||||
* 缓存组
|
|
||||||
*/
|
|
||||||
private List<CacheGroup> cacheGroup;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public static class SingleServerConfig {
|
public static class SingleServerConfig {
|
||||||
@ -141,30 +134,4 @@ public class RedissonProperties {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
|
||||||
@NoArgsConstructor
|
|
||||||
public static class CacheGroup {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 组id
|
|
||||||
*/
|
|
||||||
private String groupId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 组过期时间
|
|
||||||
*/
|
|
||||||
private long ttl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 组最大空闲时间
|
|
||||||
*/
|
|
||||||
private long maxIdleTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 组最大长度
|
|
||||||
*/
|
|
||||||
private int maxSize;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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.ruoyi.framework.manager;
|
||||||
|
|
||||||
|
import com.ruoyi.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());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user