如何在Kotlin暂停函数中使用@Cacheable

问题描述

我在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是普通对象,不需要特殊参数。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...