问题描述
我在Kotlin和Spring Boot项目中工作,我试图使用caffeine进行缓存。我有一个带有挂起功能的服务,可以进行http调用。这是我的配置:
@Bean
open fun caffeineConfig(): @NonNull caffeine<Any,Any> {
return caffeine.newBuilder().expireAfterWrite(60,TimeUnit.SECONDS)
}
@Bean
open fun cacheManager(caffeine: caffeine<Any,Any>): CacheManager {
val caffeineCacheManager = caffeineCacheManager()
caffeineCacheManager.getCache("test")
caffeineCacheManager.setcaffeine(caffeine)
return caffeineCacheManager
}
这是我要缓存的功能:
@Cacheable(value = ["test"])
open suspend fun getString(id: String): String {
return client.getString(id)
}
但是似乎缓存无法正常工作,因为从日志中可以看到,每次调用服务功能时都会调用客户端。 @Cacheable
是否不适用于暂停功能?还是我想念其他东西?
解决方法
@Cacheable
的文档中说:
每次调用建议的方法时,都会应用缓存行为,检查是否已为给定参数调用了该方法。合理的默认值只是使用方法参数来计算键,但是可以通过key()属性提供SpEL表达式,或者自定义KeyGenerator实现可以替换默认值(请参见keyGenerator())。
suspend
修饰符在生成的代码中插入一个Continuation<String>
参数,该参数接受来自调用者的输入。据推测,这意味着每次调用都有自己的延续,并且缓存将其检测为唯一调用。
但是,由于返回值也根据连续性而改变,因此您不能让缓存忽略连续性参数。更好的方法是不使用suspend
函数,而返回消费者可以共享的Deferred
:
@Cacheable(value = ["test"])
open fun getString(id: String): Deferred<String> {
return someScope.async {
client.getString(id)
}
}
// Consumer side
getString(id).await()
这应该与标准缓存机制一起使用,因为Deferred
是普通对象,不需要特殊参数。