From 89c1e4f91de2a527ec825c76b0de5dd2fd42cc59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?=
<15040126243@163.com>
Date: Sat, 13 Aug 2022 11:30:33 +0800
Subject: [PATCH] =?UTF-8?q?update=20=E9=87=8D=E5=86=99=20spring-cache=20?=
=?UTF-8?q?=E5=AE=9E=E7=8E=B0=20=E6=9B=B4=E4=BA=BA=E6=80=A7=E5=8C=96?=
=?UTF-8?q?=E7=9A=84=E6=93=8D=E4=BD=9C=20=E6=94=AF=E6=8C=81=E6=B3=A8?=
=?UTF-8?q?=E8=A7=A3=E6=8C=87=E5=AE=9Attl=E7=AD=89=E4=B8=80=E4=BA=9B?=
=?UTF-8?q?=E5=8F=82=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/main/resources/application.yml | 15 --
.../com/ruoyi/common/constant/CacheNames.java | 23 +++
.../demo/controller/RedisCacheController.java | 19 +-
.../ruoyi/framework/config/RedisConfig.java | 21 +-
.../config/properties/RedissonProperties.java | 37 +---
.../manager/PlusSpringCacheManager.java | 191 ++++++++++++++++++
6 files changed, 230 insertions(+), 76 deletions(-)
create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheNames.java
create mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/manager/PlusSpringCacheManager.java
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 4c54de53d..aef309ee3 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -233,21 +233,6 @@ thread-pool:
# 线程池维护线程所允许的空闲时间
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:
# 获取分布式锁超时时间,默认为 3000 毫秒
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheNames.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheNames.java
new file mode 100644
index 000000000..892de005d
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheNames.java
@@ -0,0 +1,23 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 缓存组名称常量
+ *
+ * key 格式为 cacheNames#ttl#maxIdleTime#maxSize
+ *
+ * ttl 过期时间 如果设置为0则不过期 默认为0
+ * maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0
+ * maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0
+ *
+ * 例子: 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";
+
+}
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java
index 2312aab0e..7342cba98 100644
--- a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java
@@ -1,5 +1,6 @@
package com.ruoyi.demo.controller;
+import com.ruoyi.common.constant.CacheNames;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.redis.RedisUtils;
import lombok.RequiredArgsConstructor;
@@ -18,7 +19,7 @@ import java.time.Duration;
* @author Lion Li
*/
// 类级别 缓存统一配置
-//@CacheConfig(cacheNames = "redissonCacheMap")
+//@CacheConfig(cacheNames = CacheNames.DEMO_CACHE)
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/cache")
@@ -36,9 +37,9 @@ public class RedisCacheController {
* 重点说明: 缓存注解严谨与其他筛选数据功能一起使用
* 例如: 数据权限注解 会造成 缓存击穿 与 数据不一致问题
*
- * 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")
public R test1(String key, String value) {
return R.ok("操作成功", value);
@@ -48,11 +49,11 @@ public class RedisCacheController {
* 测试 @CachePut
*
* 加了@CachePut注解的方法,会把方法的返回值put到缓存里面缓存起来,供其它地方使用
- * 它「通常用在新增方法上」
+ * 它「通常用在新增或者实时更新方法上」
*
- * 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")
public R test2(String key, String value) {
return R.ok("操作成功", value);
@@ -62,11 +63,11 @@ public class RedisCacheController {
* 测试 @CacheEvict
*
* 使用了CacheEvict注解的方法,会清空指定缓存
- * 「一般用在更新或者删除的方法上」
+ * 「一般用在删除的方法上」
*
- * 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")
public R test3(String key, String value) {
return R.ok("操作成功", value);
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
index c86952871..9a7938a4b 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
@@ -4,11 +4,9 @@ import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.framework.config.properties.RedissonProperties;
import com.ruoyi.framework.handler.KeyPrefixHandler;
+import com.ruoyi.framework.manager.PlusSpringCacheManager;
import lombok.extern.slf4j.Slf4j;
-import org.redisson.api.RedissonClient;
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.springframework.beans.factory.annotation.Autowired;
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.Configuration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
/**
* redis配置
*
@@ -80,18 +74,11 @@ public class RedisConfig extends CachingConfigurerSupport {
}
/**
- * 整合spring-cache
+ * 自定义缓存管理器 整合spring-cache
*/
@Bean
- public CacheManager cacheManager(RedissonClient redissonClient) {
- List cacheGroup = redissonProperties.getCacheGroup();
- Map 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));
+ public CacheManager cacheManager() {
+ return new PlusSpringCacheManager();
}
/**
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RedissonProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RedissonProperties.java
index eab746c8b..b0bf285f3 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RedissonProperties.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RedissonProperties.java
@@ -7,8 +7,6 @@ import org.redisson.config.SubscriptionMode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
-import java.util.List;
-
/**
* Redisson 配置属性
*
@@ -18,12 +16,12 @@ import java.util.List;
@Component
@ConfigurationProperties(prefix = "redisson")
public class RedissonProperties {
-
+
/**
* redis缓存key前缀
*/
private String keyPrefix;
-
+
/**
* 线程池数量,默认值 = 当前处理核数量 * 2
*/
@@ -44,11 +42,6 @@ public class RedissonProperties {
*/
private ClusterServersConfig clusterServersConfig;
- /**
- * 缓存组
- */
- private List cacheGroup;
-
@Data
@NoArgsConstructor
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;
-
- }
-
}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/PlusSpringCacheManager.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/PlusSpringCacheManager.java
new file mode 100644
index 000000000..d8bfce7c5
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/PlusSpringCacheManager.java
@@ -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.
+ *
+ * 修改 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 configMap = new ConcurrentHashMap<>();
+ ConcurrentMap instanceMap = new ConcurrentHashMap<>();
+
+ /**
+ * Creates CacheManager supplied by Redisson instance
+ */
+ public PlusSpringCacheManager() {
+ }
+
+
+ /**
+ * Defines possibility of storing {@code null} values.
+ *
+ * Default is true
+ *
+ * @param allowNullValues stores if true
+ */
+ 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.
+ *
+ * Default is false
+ *
+ * @param transactionAware cache is transaction aware if true
+ */
+ 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.
+ *
+ * `null` parameter setups dynamic mode
+ *
+ * @param names of caches
+ */
+ public void setCacheNames(Collection 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 config) {
+ this.configMap = (Map) 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 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 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 getCacheNames() {
+ return Collections.unmodifiableSet(configMap.keySet());
+ }
+
+
+}