柏竹 柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档

柏竹

奋斗柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档
  • Java基础

  • JavaWeb

  • 拓展技术

  • 框架技术

  • 数据库

  • 数据结构

  • Spring

  • SpringMVC

  • SpringBoot

  • SpringClound

  • Ruoyi-Vue-Plus

    • ruoyi-vue-plus-基础功能
    • ruoyi-vue-plus-权限控制
    • ruoyi-vue-plus-表格操作
    • ruoyi-vue-plus-缓存功能
      • 注解缓存
        • 应用前置配置
        • PlusSpringCacheManager类 缓存管理
        • 实现应用
        • 组合式缓存
    • ruoyi-vue-plus-日志功能
    • ruoyi-vue-plus-线程相关
    • ruoyi-vue-plus-OSS功能
    • ruoyi-vue-plus-代码生成功能
    • ruoyi-vue-plus-多数据源
    • ruoyi-vue-plus-任务调度
    • ruoyi-vue-plus-监控功能
    • ruoyi-vue-plus-国际化
    • ruoyi-vue-plus-XSS功能
    • ruoyi-vue-plus-防重幂&限流 功能
    • ruoyi-vue-plus-推送功能
    • ruoyi-vue-plus-序列化功能
    • ruoyi-vue-plus-数据加密
    • ruoyi-vue-plus-单元测试
    • ruoyi-vue-plus-前端插件
    • ruoyi-vue-plus-前端工具篇
    • ruoyi-vue-plus-部署篇
    • ruoyi-vue-plus-前端篇
    • ruoyi-vue-plus-后端工具篇
    • ruoyi-vue-plus-框架篇
    • ruoyi-vue-plus-问题解决
  • 后端
  • Ruoyi-Vue-Plus
柏竹
2023-11-14
目录

ruoyi-vue-plus-缓存功能

# 注解缓存

Spring提供了 SpringCache 注解缓存机制 , 能够在方法级别进行缓存数据

涉及注解

注解 说明
@Cacheable 缓存方法返回数据 , 下次调用不会进入方法体
@CachePut 更新缓存 , 将返回数据覆盖原有的数据
@CacheEvict 清除缓存 (最好追加清除条件)
@Caching 组合缓存 , 组合以上注解共同实现

常用注解参数说明

参数值 说明
String[] value cacheNames别名应用
String[] cacheNames 缓存key名称
String key 缓存field名称 (Map中的Key) (支持 SpEL语法)
String condition 条件缓存 , 在方法执行前判断 , 满足则缓存 (支持 SpEL语法)
String unless 条件缓存 , 在方法执行后判断 , 满足则不缓存 (支持 SpEL语法)
boolean sync 方法同步 . 确保高并发时 , 首次访问缓存后 , 下一次访问缓存必须生效 (避免一次性击穿问题)

支持SpEL语法 可以控制拿到 请求参数 , 响应数据

  • 请求参数获取 : #参数名
  • 响应数据获取 : #result

# 应用前置配置

RedisConfig配置类中 启用缓存管理功能@EanbleCaching注解

/**
 * 自定义缓存管理器 整合spring-cache
 */
@Bean
public CacheManager cacheManager() {
    return new PlusSpringCacheManager();
}

# PlusSpringCacheManager类 缓存管理

模仿 RedissonSpringCacheManager类源码 重写 cacheName 处理方法

核心接口 :

  • Cache 缓存对象操作接口 , 为缓存对象定义规范 , 包含各种缓存操作集合
  • CacheManager 提供各种xxxCache的实现 (支持其他缓存 , 如Redis)

意图 : 实现控制控制缓存 过期时间 / 活跃过期 / 最大缓存 缓存配置 , 在设置CacheNames时配置Redis , 使其缓存更合理的使用

例子 : test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500

顺序 标识 单位 说明
1 ttl 时长(s,m,h,d) 过期时间 (0则不过期 默认为0)
2 maxIdleTime 时长(s,m,h,d) 最大空闲时间 指定活跃过期 (0则不检测 默认为0)
3 maxSize 数值 缓存最大长度 (0则无限长 默认为0)

注意

  • 一定要遵循顺序配置以上信息
  • maxSize 一旦超过该数值会将最旧的数据进行清空

源码

核心实现方法 PlusSpringCacheManager#getCache()

点击展开













































































 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 







































@SuppressWarnings("unchecked")
public class PlusSpringCacheManager implements CacheManager {
    // 是否动态缓存
    private boolean dynamic = true;
    // 是否允许缓存存null值
    private boolean allowNullValues = true;
    // 是否使用事务
    private boolean transactionAware = true;
    /**
     * 一样对应的 缓存配置 和 缓存数据
     * 采用 ConcurrentHashMap 保证线程安全
     */
    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) {
        // 重写 cacheName 支持多参数
        String[] array = StringUtils.delimitedListToStringArray(name, "#");
        name = array[0];
        // 取取缓存实例
        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);
        }

        // 缓存数据控制 1:过期时间 , 2:最大空闲时间, 3:最大缓存数
        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());
    }


}

# 实现应用

仅作示例 , 以下示例 为了方便演示 在Controller层实现 , 一般情况会在 Service实现类的方法写 注解缓存

点击展开
@RestController
@SaIgnore
@RequestMapping("/demo/cache")
public class TestRedisCacheController {

    // test
    @Cacheable(value = "/test")
    @GetMapping("/t1")
    public String test01(SysUser user) {
        System.out.println("user = " + user);
        return "t1";
    }

    // 成员变量测试
    @Cacheable(value = "test2" , key = "#user.userId")
    @GetMapping("/t2")
    public String test02(SysUser user) {
        System.out.println("user2 = " + user);
        return "t2";
    }

    // 普通方法测试
    @Cacheable(value = "test3" , key = "#user.getTestUserId()")
    @GetMapping("/t3")
    public String test03(SysUser user) {
        System.out.println("user3 = " + user);
        return "t3";
    }

    // JSON测试
    @Cacheable(value = "test4" , key = "#user.getTestUserId()")
    @PostMapping("/t4")
    public String test04(@RequestBody SysUser user) {
        System.out.println("user4 = " + user);
        return "t4";
    }

    // 套娃对象测试赛
    @Cacheable(value = "test5" , key = "#user.student.getTestUserId()")
    @PostMapping("/t5")
    public String test05(@RequestBody SysUser user) {
        System.out.println("user5 = " + user);
        return "t5";
    }

    // 判断控制
    @Cacheable(value = "test6" , key = "#user.student.getTestUserId()" , condition = "#user.userId != null")
    @PostMapping("/t6")
    public String test06(@RequestBody SysUser user) {
        System.out.println("user6 = " + user);
        return "t6";
    }

    // 判断控制
    @Cacheable(value = "test7" , key = "#user.userId" , unless = "#result == null")
    @PostMapping("/t7")
    public String test07(@RequestBody SysUser user) {
        System.out.println("user7 = " + user);
        return user.getUserName();
    }

    // 异步测试
    @Cacheable(value = "test8" , key = "#user.userId" , sync = true)
    @PostMapping("/t8")
    public String test08(@RequestBody SysUser user) {
        System.out.println("user8 = " + user);
        ThreadUtil.sleep(5000);
        return user.getUserName();
    }
    
    // 携带Redis基础信息配置缓存
    @Cacheable(cacheNames = "test09#60s#10m#20", key = "#key", condition = "#key != null")
    @GetMapping("/t9")
    public R<String> test09(String key, String value) {
        return R.ok("操作成功", value);
    }
    
    // 更新缓存
    @CachePut(cacheNames = "test10#60s#10m#20", key = "#key", condition = "#key != null")
    @GetMapping("/t10")
    public R<String> test10(String key, String value) {
        return R.ok("操作成功", value);
    }
    
    // 清除缓存
    @CacheEvict(cacheNames = "test10", key = "#key", condition = "#key != null")
    @GetMapping("/t11")
    public R<String> test11(String key, String value) {
        return R.ok("操作成功", value);
    }

}

# 组合式缓存

组合式缓存

@Caching注解 , 一个方法多项缓存策略 , 在参数中再次写 @Cacheable / @CachePut / @CacheEvict 缓存

Caching注解参数 说明
Cacheable[] cacheable 存 缓存注解
CachePut[] put 更新 缓存注解
CacheEvict[] evict 移除 缓存注解
#ruoyi-vue-plus

← ruoyi-vue-plus-表格操作 ruoyi-vue-plus-日志功能→

最近更新
01
HTTPS自动续签
10-21
02
博客搭建-简化版(脚本)
10-20
03
ruoyi-vue-plus-部署篇
07-13
更多文章>
Theme by Vdoing | Copyright © 2019-2024 | 桂ICP备2022009417号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式