SpringBoot 改造 Spring-Cache 注解实现 支持注解指定扩展参数

整合 Redisson

参考文章: https://lionli.blog.csdn.net/article/details/117463657 参考项目: https://gitee.com/JavaLionLi/RuoYi-Vue-Plus

查看 Redisson 自带的 RedissonSpringCacheManager 缓存管理器实现

SpringBoot 改造 Spring-Cache 注解实现 支持注解指定扩展参数

查看获取 getCache 方法SpringBoot 改造 Spring-Cache 注解实现 支持注解指定扩展参数

RedissonSpringData-Redis 实现多了一些特性支持

查看 CacheConfig 配置类SpringBoot 改造 Spring-Cache 注解实现 支持注解指定扩展参数

  • ttl 过期时间 如果设置为0则不过期 默认为0
  • maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0
  • maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0

改造 RedissonSpringCacheManager 实现注解 cacheNames 定义参数

RedissonSpringCacheManager 复制到一个新的java类 PlusSpringCacheManager

我们希望支持如下格式的写法 例如: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500

改造 getCache 方法在 createMap 之前对自定义参数做解析并设置到配置类里

SpringBoot 改造 Spring-Cache 注解实现 支持注解指定扩展参数

配置使用我们自己的 CacheManager

/**
 * spring-cache 配置
 *
 * @author Lion Li
 */

@Configuration
@EnableCaching
public class SpringCacheConfig extends CachingConfigurerSupport {

    /**
     * 自定义缓存管理器 整合spring-cache
     */

    @Bean
    public CacheManager cacheManager(RedissonClient redissonClient) {
        return new PlusSpringCacheManager(redissonClient);
    }

}

完整 PlusSpringCacheManager 代码

/**
 * 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;
    private RedissonClient redissonClient;

    Map<String, CacheConfig> configMap = new ConcurrentHashMap<>();
    ConcurrentMap<String, Cache> instanceMap = new ConcurrentHashMap<>();

    /**
     * Creates CacheManager supplied by Redisson instance
     */

    public PlusSpringCacheManager(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }


    /**
     * 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 = redissonClient.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 = redissonClient.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());
    }


}

测试功能

/**
 * spring-cache 演示案例
 *
 * @author Lion Li
 */

// 类级别 缓存统一配置
//@CacheConfig(cacheNames = "demo:cache#60s#10m#20")
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/cache")
public class RedisCacheController {

    /**
     * 测试 @Cacheable
     * <p>
     * 表示这个方法有了缓存的功能,方法的返回值会被缓存下来
     * 下一次调用该方法前,会去检查是否缓存中已经有值
     * 如果有就直接返回,不调用方法
     * 如果没有,就调用方法,然后把结果缓存起来
     * 这个注解「一般用在查询方法上」
     * <p>
     * 重点说明: 缓存注解严谨与其他筛选数据功能一起使用
     * 例如: 数据权限注解 会造成 缓存击穿 与 数据不一致问题
     * <p>
     * cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数
     */

    @Cacheable(cacheNames = "demo:cache#60s#10m#20", key = "#key", condition = "#key != null")
    @GetMapping("/test1")
    public R<String> test1(String key, String value) {
        return R.ok("操作成功", value);
    }

    /**
     * 测试 @CachePut
     * <p>
     * 加了@CachePut注解的方法,会把方法的返回值put到缓存里面缓存起来,供其它地方使用
     * 它「通常用在新增或者实时更新方法上」
     * <p>
     * cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数
     */

    @CachePut(cacheNames = "demo:cache#60s#10m#20", key = "#key", condition = "#key != null")
    @GetMapping("/test2")
    public R<String> test2(String key, String value) {
        return R.ok("操作成功", value);
    }

    /**
     * 测试 @CacheEvict
     * <p>
     * 使用了CacheEvict注解的方法,会清空指定缓存
     * 「一般用在删除的方法上」
     * <p>
     * cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数
     */

    @CacheEvict(cacheNames = "demo:cache#60s#10m#20", key = "#key", condition = "#key != null")
    @GetMapping("/test3")
    public R<String> test3(String key, String value) {
        return R.ok("操作成功", value);
    }

}


原文始发于微信公众号(狮子领域 程序圈):SpringBoot 改造 Spring-Cache 注解实现 支持注解指定扩展参数

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/215153.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!