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

Spring Boot中使用@Cacheable将可序列化Kotlin数据类缓存至Redis时遇到反序列化异常求助

Spring Boot中使用@Cacheable将可序列化Kotlin数据类缓存至Redis时遇到反序列化异常求助

嗨,我之前刚踩过几乎一模一样的坑!咱们先搞清楚问题出在哪,再一步步解决它~

问题根源

你现在用的是Spring Data Redis默认的JdkSerializationRedisSerializer,这个序列化器基于Java原生序列化机制,要求被序列化的类实现java.io.Serializable接口。但你给TrainDetails加的是Kotlinx Serialization的@Serializable注解——这是Kotlin专属的序列化体系,和Java原生序列化完全不兼容,所以反序列化时自然会报错啦。

解决方案:替换Redis序列化器

有两种常用方案,你可以根据项目情况选择:

方案一:用Kotlinx Serialization实现自定义Redis序列化器

既然已经引入了Kotlinx Serialization的依赖和插件,咱们直接写一个适配Redis的序列化器:

首先创建序列化器类:

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

class KotlinxRedisSerializer<T>(private val serializer: KSerializer<T>) : RedisSerializer<T> {
    private val json = Json { 
        ignoreUnknownKeys = true // 兼容字段变更
        encodeDefaults = true // 序列化默认值
    }

    override fun serialize(t: T?): ByteArray? {
        return t?.let { json.encodeToString(serializer, it).toByteArray(StandardCharsets.UTF_8) }
    }

    override fun deserialize(bytes: ByteArray?): T? {
        return bytes?.let { json.decodeFromString(serializer, String(it, StandardCharsets.UTF_8)) }
    }
}

然后配置Redis缓存管理器,让它使用这个序列化器:

import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.cache.RedisCacheConfiguration
import org.springframework.data.redis.cache.RedisCacheManager
import org.springframework.data.redis.connection.RedisConnectionFactory
import org.springframework.data.redis.serializer.RedisSerializationContext
import org.springframework.data.redis.serializer.StringRedisSerializer

@Configuration
@EnableCaching
class RedisCacheConfig {

    @Bean
    fun redisCacheManager(connectionFactory: RedisConnectionFactory): RedisCacheManager {
        // 指定TrainDetails的序列化器
        val trainDetailsSerializer = KotlinxRedisSerializer(TrainDetails.serializer())

        val cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
            // 键用字符串序列化
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))
            // 值用自定义的Kotlinx序列化器
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(trainDetailsSerializer))

        return RedisCacheManager.builder(connectionFactory)
            .cacheDefaults(cacheConfig)
            .build()
    }
}

方案二:用Jackson配合Kotlin模块(更省心)

如果不想写自定义序列化器,也可以用Spring默认支持的Jackson来处理Kotlin数据类:

首先确保依赖里加了Jackson的Kotlin模块(Gradle Kotlin DSL为例):

implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

然后配置缓存管理器:

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.cache.RedisCacheConfiguration
import org.springframework.data.redis.cache.RedisCacheManager
import org.springframework.data.redis.connection.RedisConnectionFactory
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer
import org.springframework.data.redis.serializer.RedisSerializationContext
import org.springframework.data.redis.serializer.StringRedisSerializer

@Configuration
@EnableCaching
class RedisCacheConfig {

    @Bean
    fun objectMapper(): ObjectMapper {
        // 注册Kotlin模块,让Jackson能正确处理Kotlin数据类
        return ObjectMapper().registerKotlinModule()
    }

    @Bean
    fun redisCacheManager(connectionFactory: RedisConnectionFactory, objectMapper: ObjectMapper): RedisCacheManager {
        val jacksonSerializer = Jackson2JsonRedisSerializer(TrainDetails::class.java).apply {
            setObjectMapper(objectMapper)
        }

        val cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSerializer))

        return RedisCacheManager.builder(connectionFactory)
            .cacheDefaults(cacheConfig)
            .build()
    }
}

最后别忘了清理旧缓存!

如果你之前已经用JDK序列化存过数据到Redis,一定要先清空对应的缓存键(比如Schedule相关的键),不然新的序列化器还是读不懂旧格式的数据,会继续报错哦~

内容来源于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:38:05