You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring Redis Cache中结合Kotlinx Serialization实现多数据类的序列化与反序列化?

如何在Spring Redis Cache中结合Kotlinx Serialization实现多数据类的序列化与反序列化?

你完全不用给每个数据类都单独写一套RedisCacheConfiguration,针对你有10个数据类的场景,咱们可以用批量配置缓存映射的方式来简化代码,既保持灵活性又避免重复劳动。

方案一:基于缓存名-序列化器映射的批量配置

这个思路很直接:先维护一个「缓存名对应数据类序列化器」的映射表,然后批量生成每个缓存的专属配置,最后交给RedisCacheManager统一管理。

第一步:维护缓存名与序列化器的映射

先把你所有需要缓存的数据类对应的缓存名和序列化器整理到一个Map里:

// 可以放在配置类里作为一个属性
private val cacheSerializerMap = mapOf(
    "trainStatus" to TrainStatus.serializer(),
    "trainSchedule" to TrainSchedule.serializer(),
    "userDetails" to UserDetails.serializer(),
    // 剩下的7个数据类依次添加进来即可
)

第二步:改造CacheManager配置

基于你的现有代码,扩展成批量配置的形式:

@Bean
fun cacheManager(redisConnectionFactory: RedisConnectionFactory): CacheManager {
    // 先定义通用的基础缓存配置(键序列化、过期时间等)
    val defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
        .entryTtl(Duration.ofDays(1))
        .serializeKeysWith(
            RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer())
        )

    // 批量生成每个缓存名对应的专属配置(仅覆盖值序列化器)
    val cacheSpecificConfigs = cacheSerializerMap.mapValues { (_, serializer) ->
        defaultCacheConfig.serializeValuesWith(
            RedisSerializationContext.SerializationPair.fromSerializer(
                KotlinSerializationRedisSerializer(serializer)
            )
        )
    }

    return RedisCacheManager.builder(redisConnectionFactory)
        .cacheDefaults(defaultCacheConfig) // 未在映射表中的缓存使用默认配置
        .withInitialCacheConfigurations(cacheSpecificConfigs) // 加载批量配置的缓存
        .build()
}

第三步:正常使用@Cacheable

这样你就可以像最开始期望的那样,直接通过缓存名指定对应的缓存操作,Redis会自动匹配到正确的序列化器:

@Cacheable("trainStatus")
suspend fun getTrainStatus(...): TrainStatus

@Cacheable("userDetails")
fun getUser(...): UserDetails

为什么这个方案适合你?

  • 维护成本低:新增数据类时,只需要在cacheSerializerMap里加一行映射即可,不用修改CacheManager的核心逻辑
  • 保留原有序列化器:你写的KotlinSerializationRedisSerializer完全可以继续用,不用做任何修改
  • 灵活性高:如果某个缓存需要特殊配置(比如不同的过期时间),可以单独在映射里覆盖对应的配置

进阶思路:通用自动推断序列化器(可选)

如果你不想维护这个映射表,也可以尝试改造序列化器,让它能通过反射自动获取数据类的序列化器。不过这里有个前提:Redis存储的缓存值需要附带类型信息,否则反序列化时无法推断目标类型。

改造后的通用序列化器示例:

import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.serializer
import org.springframework.data.redis.serializer.RedisSerializer
import java.nio.charset.Charsets

class GenericKotlinxRedisSerializer(
    private val json: Json = Json
) : RedisSerializer<Any> {

    @Suppress("UNCHECKED_CAST")
    override fun serialize(t: Any?): ByteArray? {
        return t?.let {
            // 通过反射获取当前对象的序列化器
            val serializer = serializer(it::class.java) as KSerializer<Any>
            json.encodeToString(serializer, it).toByteArray(Charsets.UTF_8)
        }
    }

    @Suppress("UNCHECKED_CAST")
    override fun deserialize(bytes: ByteArray?): Any? {
        // 注意:这里默认无法直接反序列化,因为缺少类型信息
        // 实际使用时需要结合Spring的缓存上下文获取目标类型,或者在序列化时存入类型信息
        throw UnsupportedOperationException("请结合具体类型调用带类型参数的反序列化方法")
    }

    // 供Spring内部调用的带类型参数的反序列化方法
    @Suppress("UNCHECKED_CAST")
    fun <T> deserialize(bytes: ByteArray?, targetType: Class<T>): T? {
        return bytes?.let {
            val serializer = serializer(targetType) as KSerializer<T>
            json.decodeFromString(serializer, String(it, Charsets.UTF_8))
        }
    }
}

不过这个进阶方案需要额外处理Spring缓存的类型传递逻辑,相对复杂一些。如果你的数据类数量固定在10个左右,前面的批量映射方案会更简单直接。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 13:29:32