From 6d484c0bdaa1983f2a7e25666fd01e2aa62db85c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=B0=8F=E7=8E=8B=E5=AD=90?= Date: Wed, 28 Feb 2024 14:40:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=95=E5=85=A5caffeine=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 8 ++ .../main/java/com/ruoyi/RuoYiApplication.java | 5 +- ruoyi-common/ruoyi-common-redis/pom.xml | 6 ++ .../common/redis/config/CacheConfig.java | 45 ++++++++++ .../common/redis/config/RedisConfig.java | 17 +--- .../redis/manager/CaffeineCacheDecorator.java | 88 +++++++++++++++++++ .../redis/manager/FlexSpringCacheManager.java | 6 +- ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-security/pom.xml | 6 ++ .../security/core/dao/FlexSaTokenDao.java | 35 ++++++-- .../service/impl/SysDictTypeServiceImpl.java | 16 +--- 11 files changed, 197 insertions(+), 36 deletions(-) create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/CacheConfig.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/manager/CaffeineCacheDecorator.java diff --git a/pom.xml b/pom.xml index f8220ef..ebfa899 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,7 @@ 1.37.0 5.1.0 1.21 + 3.1.8 2.3.3 6.1.0 2.0.43 @@ -172,6 +173,13 @@ ${satoken.version} + + + com.github.ben-manes.caffeine + caffeine + ${caffeine.version} + + jakarta.servlet diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java index 5bb5581..cdc5486 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java @@ -3,6 +3,7 @@ package com.ruoyi; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration; +import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; /** * 启动程序 @@ -14,7 +15,9 @@ public class RuoYiApplication { public static void main(String[] args) { - SpringApplication.run(RuoYiApplication.class, args); + SpringApplication application = new SpringApplication(RuoYiApplication.class); + application.setApplicationStartup(new BufferingApplicationStartup(2048)); + application.run(args); System.out.println("(♥◠‿◠)ノ゙ RuoYi-Flex-Boot启动成功 ლ(´ڡ`ლ)゙ \n" + " ███████ ██ ██ ██ ████████ ██ \n" + "░██░░░░██ ░░██ ██ ░░ ░██░░░░░ ░██ \n" + diff --git a/ruoyi-common/ruoyi-common-redis/pom.xml b/ruoyi-common/ruoyi-common-redis/pom.xml index bf59aec..a6a60b5 100644 --- a/ruoyi-common/ruoyi-common-redis/pom.xml +++ b/ruoyi-common/ruoyi-common-redis/pom.xml @@ -46,6 +46,12 @@ spring-boot-configuration-processor + + + com.github.ben-manes.caffeine + caffeine + + diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/CacheConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/CacheConfig.java new file mode 100644 index 0000000..257a4e6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/CacheConfig.java @@ -0,0 +1,45 @@ +package com.ruoyi.common.redis.config; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.ruoyi.common.redis.manager.FlexSpringCacheManager; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; + +import java.util.concurrent.TimeUnit; + +/** + * 缓存配置 + * + * @author Lion Li + */ +@AutoConfiguration +@EnableCaching +public class CacheConfig { + + /** + * caffeine 本地缓存处理器 + */ + @Bean + public Cache caffeine() { + return Caffeine.newBuilder() + // 设置最后一次写入或访问后经过固定时间过期 + .expireAfterWrite(30, TimeUnit.SECONDS) + // 初始的缓存空间大小 + .initialCapacity(100) + // 缓存的最大条数 + .maximumSize(1000) + .build(); + } + + /** + * 自定义缓存管理器 整合spring-cache + */ + @Bean + public CacheManager cacheManager() { + return new FlexSpringCacheManager(); + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/RedisConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/RedisConfig.java index 63c3a8e..4064569 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/RedisConfig.java +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/RedisConfig.java @@ -5,8 +5,8 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import lombok.extern.slf4j.Slf4j; import com.ruoyi.common.redis.handler.KeyPrefixHandler; -import com.ruoyi.common.redis.manager.FlexSpringCacheManager; import com.ruoyi.common.redis.config.properties.RedissonProperties; import jakarta.annotation.Resource; import org.redisson.client.codec.StringCodec; @@ -16,22 +16,17 @@ import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfiguration; 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.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * redis配置 * * @author Lion Li */ +@Slf4j @AutoConfiguration -@EnableCaching @EnableConfigurationProperties(RedissonProperties.class) public class RedisConfig { - private static final Logger log = LoggerFactory.getLogger(RedisConfig.class); @Autowired private RedissonProperties redissonProperties; @Resource @@ -86,14 +81,6 @@ public class RedisConfig { }; } - /** - * 自定义缓存管理器 整合spring-cache - */ - @Bean - public CacheManager cacheManager() { - return new FlexSpringCacheManager(); - } - /** * redis集群配置 yml * diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/manager/CaffeineCacheDecorator.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/manager/CaffeineCacheDecorator.java new file mode 100644 index 0000000..d299102 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/manager/CaffeineCacheDecorator.java @@ -0,0 +1,88 @@ +package com.ruoyi.common.redis.manager; + +import com.ruoyi.common.core.utils.SpringUtils; +import org.springframework.cache.Cache; + +import java.util.concurrent.Callable; + +/** + * Cache 装饰器模式(用于扩展 Caffeine 一级缓存) + * + * @author LionLi + */ +public class CaffeineCacheDecorator implements Cache { + + private static final com.github.benmanes.caffeine.cache.Cache + CAFFEINE = SpringUtils.getBean("caffeine"); + + private final Cache cache; + + public CaffeineCacheDecorator(Cache cache) { + this.cache = cache; + } + + @Override + public String getName() { + return cache.getName(); + } + + @Override + public Object getNativeCache() { + return cache.getNativeCache(); + } + + public String getUniqueKey(Object key) { + return cache.getName() + ":" + key; + } + + @Override + public ValueWrapper get(Object key) { + Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key)); + return (ValueWrapper) o; + } + + @SuppressWarnings("unchecked") + public T get(Object key, Class type) { + Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, type)); + return (T) o; + } + + @Override + public void put(Object key, Object value) { + cache.put(key, value); + } + + public ValueWrapper putIfAbsent(Object key, Object value) { + return cache.putIfAbsent(key, value); + } + + @Override + public void evict(Object key) { + evictIfPresent(key); + } + + public boolean evictIfPresent(Object key) { + boolean b = cache.evictIfPresent(key); + if (b) { + CAFFEINE.invalidate(getUniqueKey(key)); + } + return b; + } + + @Override + public void clear() { + cache.clear(); + } + + public boolean invalidate() { + return cache.invalidate(); + } + + @SuppressWarnings("unchecked") + @Override + public T get(Object key, Callable valueLoader) { + Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, valueLoader)); + return (T) o; + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/manager/FlexSpringCacheManager.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/manager/FlexSpringCacheManager.java index 405a495..4f021fc 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/manager/FlexSpringCacheManager.java +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/manager/FlexSpringCacheManager.java @@ -33,7 +33,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** - * A {@link org.springframework.cache.CacheManager} implementation + * A {@link CacheManager} implementation * backed by Redisson instance. *

* 修改 RedissonSpringCacheManager 源码 @@ -156,7 +156,7 @@ public class FlexSpringCacheManager implements CacheManager { private Cache createMap(String name, CacheConfig config) { RMap map = RedisUtils.getClient().getMap(name); - Cache cache = new RedissonCache(map, allowNullValues); + Cache cache = new CaffeineCacheDecorator(new RedissonCache(map, allowNullValues)); if (transactionAware) { cache = new TransactionAwareCacheDecorator(cache); } @@ -170,7 +170,7 @@ public class FlexSpringCacheManager implements CacheManager { private Cache createMapCache(String name, CacheConfig config) { RMapCache map = RedisUtils.getClient().getMapCache(name); - Cache cache = new RedissonCache(map, config, allowNullValues); + Cache cache = new CaffeineCacheDecorator(new RedissonCache(map, config, allowNullValues)); if (transactionAware) { cache = new TransactionAwareCacheDecorator(cache); } diff --git a/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index fe5d8b9..8c23566 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1 +1,2 @@ com.ruoyi.common.redis.config.RedisConfig +com.ruoyi.common.redis.config.CacheConfig diff --git a/ruoyi-common/ruoyi-common-security/pom.xml b/ruoyi-common/ruoyi-common-security/pom.xml index 73eca43..0bfbb0b 100644 --- a/ruoyi-common/ruoyi-common-security/pom.xml +++ b/ruoyi-common/ruoyi-common-security/pom.xml @@ -41,6 +41,12 @@ sa-token-jwt + + + com.github.ben-manes.caffeine + caffeine + + diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/core/dao/FlexSaTokenDao.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/core/dao/FlexSaTokenDao.java index 627e35c..444ad5b 100644 --- a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/core/dao/FlexSaTokenDao.java +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/core/dao/FlexSaTokenDao.java @@ -2,12 +2,16 @@ package com.ruoyi.common.security.core.dao; import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.util.SaFoxUtil; +import cn.hutool.core.lang.Console; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import com.ruoyi.common.redis.utils.RedisUtils; import java.time.Duration; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.concurrent.TimeUnit; /** * Sa-Token持久层接口(使用框架自带RedisUtils实现 协议统一) @@ -16,12 +20,23 @@ import java.util.List; */ public class FlexSaTokenDao implements SaTokenDao { + private static final Cache CAFFEINE = Caffeine.newBuilder() + // 设置最后一次写入或访问后经过固定时间过期 + .expireAfterWrite(5, TimeUnit.SECONDS) + // 初始的缓存空间大小 + .initialCapacity(100) + // 缓存的最大条数 + .maximumSize(1000) + .build(); + /** * 获取Value,如无返空 */ @Override public String get(String key) { - return RedisUtils.getCacheObject(key); + Object o = CAFFEINE.get(key, k -> RedisUtils.getCacheObject(key)); + Console.log("caffeine -> key:" + key + ",value:" + o); + return (String) o; } /** @@ -38,6 +53,7 @@ public class FlexSaTokenDao implements SaTokenDao { } else { RedisUtils.setCacheObject(key, value, Duration.ofSeconds(timeout)); } + CAFFEINE.put(key, value); } /** @@ -47,6 +63,7 @@ public class FlexSaTokenDao implements SaTokenDao { public void update(String key, String value) { if (RedisUtils.hasKey(key)) { RedisUtils.setCacheObject(key, value, true); + CAFFEINE.put(key, value); } } @@ -81,7 +98,9 @@ public class FlexSaTokenDao implements SaTokenDao { */ @Override public Object getObject(String key) { - return RedisUtils.getCacheObject(key); + Object o = CAFFEINE.get(key, k -> RedisUtils.getCacheObject(key)); + Console.log("caffeine -> key:" + key + ",value:" + o); + return o; } /** @@ -98,6 +117,7 @@ public class FlexSaTokenDao implements SaTokenDao { } else { RedisUtils.setCacheObject(key, object, Duration.ofSeconds(timeout)); } + CAFFEINE.put(key, object); } /** @@ -107,6 +127,7 @@ public class FlexSaTokenDao implements SaTokenDao { public void updateObject(String key, Object object) { if (RedisUtils.hasKey(key)) { RedisUtils.setCacheObject(key, object, true); + CAFFEINE.put(key, object); } } @@ -139,10 +160,14 @@ public class FlexSaTokenDao implements SaTokenDao { /** * 搜索数据 */ + @SuppressWarnings("unchecked") @Override public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { - Collection keys = RedisUtils.keys(prefix + "*" + keyword + "*"); - List list = new ArrayList<>(keys); - return SaFoxUtil.searchList(list, start, size, sortType); + String keyStr = prefix + "*" + keyword + "*"; + return (List) CAFFEINE.get(keyStr, k -> { + Collection keys = RedisUtils.keys(keyStr); + List list = new ArrayList<>(keys); + return SaFoxUtil.searchList(list, start, size, sortType); + }); } } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java index e22e7ed..5c306be 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java @@ -236,16 +236,12 @@ public class SysDictTypeServiceImpl extends BaseServiceImpl lists = (List) SaHolder.getStorage().get(CacheConstants.SYS_DICT_KEY + dictType); + List lists = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); if (ObjectUtil.isNull(lists)) { - lists = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); - SaHolder.getStorage().set(CacheConstants.SYS_DICT_KEY + dictType, lists); + return StringUtils.EMPTY; } - Map map = StreamUtils.toMap(lists, SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel); if (StringUtils.containsAny(dictValue, separator)) { return Arrays.stream(dictValue.split(separator)) @@ -264,16 +260,12 @@ public class SysDictTypeServiceImpl extends BaseServiceImpl lists = (List) SaHolder.getStorage().get(CacheConstants.SYS_DICT_KEY + dictType); + List lists = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); if (ObjectUtil.isNull(lists)) { - lists = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); - SaHolder.getStorage().set(CacheConstants.SYS_DICT_KEY + dictType, lists); + return StringUtils.EMPTY; } - Map map = StreamUtils.toMap(lists, SysDictDataVo::getDictLabel, SysDictDataVo::getDictValue); if (StringUtils.containsAny(dictLabel, separator)) { return Arrays.stream(dictLabel.split(separator))