spring cache 支持多结构的 Redis 缓存管理器

需求背景:spring cache 使用多级缓存,缓存实现方式用redis时,默认存储的结构是string,结果,但项目中需要使用其他结果,于是想到自己定义一个实现类,然后根据类型进行切换不同的实现方式,于是乎有了下面多结构缓存管理器,核心方法是createRedisCache

复制代码
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import java.util.Map;
import java.util.Objects;

/**
 * 支持多结构的 Redis 缓存管理器
 * 可根据缓存名前缀自动选择缓存结构(Hash/ZSet/普通字符串)
 */
public class StructRedisCacheManager extends RedisCacheManager {

    // 缓存结构类型枚举
    public enum CacheStructType {
        HASH,   // Hash 结构
        ZSET,   // ZSet 结构
        STRING  // 普通字符串结构(默认)
    }

    // 结构前缀(用于标识缓存类型,例如 "hash:userCache" 表示 Hash 结构)
    private static final String HASH_PREFIX = "hash:";
    private static final String ZSET_PREFIX = "zset:";

    private final RedisConnectionFactory connectionFactory;
    // 各结构的默认配置(是否允许覆盖/重复)
    private final boolean hashAllowOverwrite;  // Hash 是否允许覆盖
    private final boolean zsetAllowDuplicate; // ZSet 是否允许重复元素

    public StructRedisCacheManager(
            RedisCacheWriter cacheWriter,
            RedisCacheConfiguration defaultCacheConfig,
            RedisConnectionFactory connectionFactory,
            boolean hashAllowOverwrite,
            boolean zsetAllowDuplicate
    ) {
        super(cacheWriter, defaultCacheConfig);
        this.connectionFactory = connectionFactory;
        this.hashAllowOverwrite = hashAllowOverwrite;
        this.zsetAllowDuplicate = zsetAllowDuplicate;
    }

    /**
     * 重载构造器(支持自定义缓存配置)
     */
    public StructRedisCacheManager(
            RedisCacheWriter cacheWriter,
            RedisCacheConfiguration defaultCacheConfig,
            Map<String, RedisCacheConfiguration> initialCacheConfigurations,
            RedisConnectionFactory connectionFactory,
            boolean hashAllowOverwrite,
            boolean zsetAllowDuplicate
    ) {
        super(cacheWriter, defaultCacheConfig, initialCacheConfigurations);
        this.connectionFactory = connectionFactory;
        this.hashAllowOverwrite = hashAllowOverwrite;
        this.zsetAllowDuplicate = zsetAllowDuplicate;
    }

    /**
     * 核心:根据缓存名选择对应的缓存结构实现
     */
    @Override
    protected RedisCache createRedisCache(String cacheName, RedisCacheConfiguration config) {
        // 解析缓存结构类型
        CacheStructType structType = parseStructType(cacheName);
        // 提取业务缓存名(去除结构前缀)
        String bizName = extractBizName(cacheName, structType);

        // 根据类型创建对应缓存实例
        switch (structType) {
            case HASH:
                // 创建 Hash 结构缓存
                return new HashRedisCache(
                        bizName,
                        getCacheWriter(),
                        config != null ? config : getDefaultCacheConfiguration(),
                        connectionFactory,
                        hashAllowOverwrite
                );
            case ZSET:
                // 创建 ZSet 结构缓存
                return new ZSetRedisCache(
                        bizName,
                        getCacheWriter(),
                        config != null ? config : getDefaultCacheConfiguration(),
                        connectionFactory,
                        zsetAllowDuplicate
                );
            default:
                // 默认使用普通字符串缓存(Spring 原生实现)
                return super.createRedisCache(bizName, config);
        }
    }

    /**
     * 解析缓存名对应的结构类型(通过前缀判断)
     */
    private CacheStructType parseStructType(String cacheName) {
        if (cacheName.startsWith(HASH_PREFIX)) {
            return CacheStructType.HASH;
        } else if (cacheName.startsWith(ZSET_PREFIX)) {
            return CacheStructType.ZSET;
        } else {
            return CacheStructType.STRING;
        }
    }

    /**
     * 提取业务缓存名(去除结构前缀)
     */
    private String extractBizName(String cacheName, CacheStructType structType) {
        switch (structType) {
            case HASH:
                return cacheName.substring(HASH_PREFIX.length());
            case ZSET:
                return cacheName.substring(ZSET_PREFIX.length());
            default:
                return cacheName;
        }
    }
}
相关推荐
需要8263 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
silvamux_5 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
XIAEE7 小时前
转生到儿童编程异世界:我用 Vue 和 Scratch 建了一座 DREAM 学院
java·spring
XIAEE8 小时前
初次使用 Node + Koa + MongoDB 搭建服务器:从零到第一个 API
java·spring
雷一言说8 小时前
Spring AI 2.0:RAG 文档分块大小策略选择
java·spring
XIAEE8 小时前
Java 世界历险记:从一行 System.out.println 到整个 Spring 宇宙
java·spring
XIAEE8 小时前
微前端狂想曲:我试图让三个不同门派的前端住进同一栋楼
java·spring
XIAEE8 小时前
Linux 生存指南:从"终端恐惧症"到"命令行老司机"
java·spring
XIAEE8 小时前
实战教程:手机端死活调不出摄像头?聊聊安全上下文(Secure Context)
java·spring
XIAEE8 小时前
ES6 与 Node.js 群侠传:那些年我们追过的语法,和那些年把我们追杀的 API
java·spring