如何通过 Jackson 使用 json 在 Redis 中轻松缓存 Kotlin 对象?
How can I easily cache Kotlin Objects in Redis using json via Jackson?
我有一个用 Kotlin 编写的 Spring 启动应用程序,我想在其中启用 Redis 中的缓存。我希望将对象存储为序列化 JSON 并且理想情况下不希望必须注册可能被缓存的每种类型。我有一些基本有效的配置,但有一个很大的警告。
@Bean
fun redisCacheConfiguration(): RedisCacheConfiguration {
val objectMapper =
ObjectMapper()
.registerModule(KotlinModule())
.registerModule(JavaTimeModule())
.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)
val serializer = GenericJackson2JsonRedisSerializer(objectMapper)
return RedisCacheConfiguration
.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
}
我有点难以理解 DefaultTyping
的不同值,但 NON_FINAL
似乎是最广泛的。然而,由于 Kotlin 中的对象默认是最终的,这只适用于标记为 "open" 的对象。理想情况下,我想避免 "open" 对象只是为了它们可以被缓存。
我还有其他方法可以完成这项工作吗?
我遇到了同样的问题。您应该使用 "open" classes。但这对数据 classes 没有帮助,因为你不能使它们 "open".
有一个名为 "all-open" 的插件,您可以在其中定义注释。如果使用这些注解 classes 就变成了 "open",即使数据 classes.
spring-kotlin 插件在后台使用 "all-open" 插件,因此 spring 像 @Service、@Component 等注解使 class 对 AOP 开放,因为代理需要你继承自 classes.
如果你使用 spring-kotlin 插件,有一个很好的注释对你的问题有意义,它被用在 Spring 缓存中,它的名字是 @Cacheable。
如果您在 classes 上使用 @Cacheable,它们将打开并将其类型信息保存到 json(例如:{@class: "com.example.MyClass", ... }) 当您包含此代码时:
val objectMapper =
ObjectMapper()
.registerModule(KotlinModule())
.registerModule(JavaTimeModule())
.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)
val serializer = GenericJackson2JsonRedisSerializer(objectMapper)
更多详情:https://kotlinlang.org/docs/reference/compiler-plugins.html
简而言之:除了向您想要的 classes 添加 @Cacheable 批注外,您无需执行任何操作,而且它在我看来也很合适。
issues已解决。因此我们可以从代码中删除 @Cacheble
hack。您必须使用下一个实现
修改 ObjectMapper
val om = ObjectMapper()
.registerModule(KotlinModule())
.registerModule(JavaTimeModule())
.activateDefaultTyping(BasicPolymorphicTypeValidator.builder()
.allowIfBaseType(Any::class.java)
.build(), ObjectMapper.DefaultTyping.EVERYTHING)
val serializer = GenericJackson2JsonRedisSerializer(om)
修复了 Maven Jackon 依赖性
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0.pr2</version>
</dependency>
你可以看这个:
https://github.com/endink/caching-kotlin
它同时支持 jackson 和 kryo
我遇到了一个问题,因为我的数据 类 正在扩展一些接口,所以泛型无法解决问题,我最终得到了这个解决方案,它是一个自定义序列化器和反序列化器,泛型只会节省时间将 getter 编译为变量并破坏反序列化
@Configuration
@EnableCaching
class CachingConfiguration() : CachingConfigurerSupport() {
@Bean
fun configureRedisAction(): ConfigureRedisAction? {
return ConfigureRedisAction.NO_OP
}
@Autowired
private lateinit var redisConnectionFactory: RedisConnectionFactory
companion object {
const val CACHE_KEY = "cache-key"
}
@Bean
override fun cacheManager(): CacheManager? {
return RedisCacheManager.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory)
.withCacheConfiguration(CACHE_KEY, cacheConfig<User>(ofMinutes(5)))
.build()
}
private inline fun <reified T> cacheConfig(ttl: Duration): RedisCacheConfiguration {
return RedisCacheConfiguration
.defaultCacheConfig()
.serializeValuesWith(fromSerializer(object : RedisSerializer<Any> {
val mapper = ObjectMapper().registerModule(ParameterNamesModule())
override fun serialize(t: Any?): ByteArray? {
return mapper.writeValueAsBytes(t)
}
override fun deserialize(bytes: ByteArray?): Any? {
return try {
mapper.readValue(bytes!!, T::class.java) as Any
} catch (e: Exception) {
null
}
}
})
)
.entryTtl(ttl)
}
}
我有一个用 Kotlin 编写的 Spring 启动应用程序,我想在其中启用 Redis 中的缓存。我希望将对象存储为序列化 JSON 并且理想情况下不希望必须注册可能被缓存的每种类型。我有一些基本有效的配置,但有一个很大的警告。
@Bean
fun redisCacheConfiguration(): RedisCacheConfiguration {
val objectMapper =
ObjectMapper()
.registerModule(KotlinModule())
.registerModule(JavaTimeModule())
.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)
val serializer = GenericJackson2JsonRedisSerializer(objectMapper)
return RedisCacheConfiguration
.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
}
我有点难以理解 DefaultTyping
的不同值,但 NON_FINAL
似乎是最广泛的。然而,由于 Kotlin 中的对象默认是最终的,这只适用于标记为 "open" 的对象。理想情况下,我想避免 "open" 对象只是为了它们可以被缓存。
我还有其他方法可以完成这项工作吗?
我遇到了同样的问题。您应该使用 "open" classes。但这对数据 classes 没有帮助,因为你不能使它们 "open".
有一个名为 "all-open" 的插件,您可以在其中定义注释。如果使用这些注解 classes 就变成了 "open",即使数据 classes.
spring-kotlin 插件在后台使用 "all-open" 插件,因此 spring 像 @Service、@Component 等注解使 class 对 AOP 开放,因为代理需要你继承自 classes.
如果你使用 spring-kotlin 插件,有一个很好的注释对你的问题有意义,它被用在 Spring 缓存中,它的名字是 @Cacheable。 如果您在 classes 上使用 @Cacheable,它们将打开并将其类型信息保存到 json(例如:{@class: "com.example.MyClass", ... }) 当您包含此代码时:
val objectMapper =
ObjectMapper()
.registerModule(KotlinModule())
.registerModule(JavaTimeModule())
.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)
val serializer = GenericJackson2JsonRedisSerializer(objectMapper)
更多详情:https://kotlinlang.org/docs/reference/compiler-plugins.html
简而言之:除了向您想要的 classes 添加 @Cacheable 批注外,您无需执行任何操作,而且它在我看来也很合适。
issues已解决。因此我们可以从代码中删除 @Cacheble
hack。您必须使用下一个实现
ObjectMapper
val om = ObjectMapper()
.registerModule(KotlinModule())
.registerModule(JavaTimeModule())
.activateDefaultTyping(BasicPolymorphicTypeValidator.builder()
.allowIfBaseType(Any::class.java)
.build(), ObjectMapper.DefaultTyping.EVERYTHING)
val serializer = GenericJackson2JsonRedisSerializer(om)
修复了 Maven Jackon 依赖性
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0.pr2</version>
</dependency>
你可以看这个:
https://github.com/endink/caching-kotlin
它同时支持 jackson 和 kryo
我遇到了一个问题,因为我的数据 类 正在扩展一些接口,所以泛型无法解决问题,我最终得到了这个解决方案,它是一个自定义序列化器和反序列化器,泛型只会节省时间将 getter 编译为变量并破坏反序列化
@Configuration
@EnableCaching
class CachingConfiguration() : CachingConfigurerSupport() {
@Bean
fun configureRedisAction(): ConfigureRedisAction? {
return ConfigureRedisAction.NO_OP
}
@Autowired
private lateinit var redisConnectionFactory: RedisConnectionFactory
companion object {
const val CACHE_KEY = "cache-key"
}
@Bean
override fun cacheManager(): CacheManager? {
return RedisCacheManager.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory)
.withCacheConfiguration(CACHE_KEY, cacheConfig<User>(ofMinutes(5)))
.build()
}
private inline fun <reified T> cacheConfig(ttl: Duration): RedisCacheConfiguration {
return RedisCacheConfiguration
.defaultCacheConfig()
.serializeValuesWith(fromSerializer(object : RedisSerializer<Any> {
val mapper = ObjectMapper().registerModule(ParameterNamesModule())
override fun serialize(t: Any?): ByteArray? {
return mapper.writeValueAsBytes(t)
}
override fun deserialize(bytes: ByteArray?): Any? {
return try {
mapper.readValue(bytes!!, T::class.java) as Any
} catch (e: Exception) {
null
}
}
})
)
.entryTtl(ttl)
}
}