如何在 "Scala" 中为 Caffeine LoadingCache 编写缓存加载程序以供 "refreshAfterWrite" 工作

How to write a cache loader for Caffeine LoadingCache in "Scala" for "refreshAfterWrite" to work

Scala 应用程序用例:

我们有一个基于 Scala 的模块从全局缓存 (Redis) 读取数据并将其保存到本地缓存 (Caffeine LoadingCache)。由于我们希望异步刷新此数据,因此我们使用 LoadingCache 并将 refreshAfterWrite 持续时间设置为刷新 window of 2.second.

问题: 不是问题,但需要以下代码的帮助,这些代码会发出警告和编译时错误

警告:对于build方法,它给出警告为Implements member load in CacheLoader (com.github.benmanes.caffeine.cache)

编译时错误1: type arguments [Int,redisToCaffeine.DataObject] conform to the bounds of none of the overloaded alternatives of value build: [K1 <: Object, V1 <: Object](x: com.github.benmanes.caffeine.cache.CacheLoader[_ >: K1, V1])com.github.benmanes.caffeine.cache.LoadingCache[K1,V1] <and> [K1 <: Object, V1 <: Object]()com.github.benmanes.caffeine.cache.Cache[K1,V1] .build[Int, DataObject](key => loader(key))

编译时错误2: wrong number of type parameters for overloaded method value build with alternatives: [K1 <: Object, V1 <: Object](x: com.github.benmanes.caffeine.cache.CacheLoader[_ >: K1, V1])com.github.benmanes.caffeine.cache.LoadingCache[K1,V1] <and> [K1 <: Object, V1 <: Object]()com.github.benmanes.caffeine.cache.Cache[K1,V1] .build[Int, DataObject](key => loader(key))

代码:

package redisToCaffeine

import scala.concurrent.duration._

import com.github.benmanes.caffeine.cache.{ CacheLoader, Caffeine, LoadingCache }
import com.twitter.finagle.stats.InMemoryStatsReceiver
import javax.annotation.Nullable
import redisToCaffeine.CacheImplicits.StatsReportingCaffeineCache

class LocalDealService {

  class DataObject(data: String) {
    override def toString: String = {
      "[ 'data': '" + this.data + "' ]"
    }
  }

  val defaultCacheExpireDuration: FiniteDuration = 2.second
  val stats: InMemoryStatsReceiver = new InMemoryStatsReceiver

  // loader helper
  @Nullable
  @throws[Exception]
  protected def loader(key: Int): DataObject = { // this will replace to read the data from Redis Cache
    new DataObject(s"LOADER_HELPER_$key")
  }

  def initCache(maximumSize: Int = 5): LoadingCache[Int, DataObject] = {
    Caffeine
      .newBuilder()
      .maximumSize(maximumSize)
      .refreshAfterWrite(defaultCacheExpireDuration.length, defaultCacheExpireDuration.unit)
      .recordStats()
      .build[Int, DataObject](key => loader(key))
      .enableCacheStatsReporting("deal-service", stats)
  }
}

我是 Scala 和 Caffeine 的新手,所以不确定我做错了什么;我尝试了 here and here 提到的不同方法来编写加载器,但没有任何效果(主要是在 Java 中)。对 Scala 边界的一些研究在这里没有任何帮助。请帮忙。

取决于这里使用的 Scala 版本。

尽管 Scala(2.12 及更高版本)函数支持转换为 Java SAM,但只有在明确需要时才会执行这些操作。所以如果你使用的是Scala 2.12或更高版本,你可以显式要求编译器将Scala函数转换为SAM,

此外,不要使用 Int 作为缓存的关键字。虽然它会因为隐式转换为 Integer 而起作用,但这不是一个好的做法。

def initCache(maximumSize: Int = 5): LoadingCache[Integer, DataObject] = {
  Caffeine
    .newBuilder()
    .maximumSize(maximumSize)
    .refreshAfterWrite(defaultCacheExpireDuration.length, defaultCacheExpireDuration.unit)
    .recordStats()
    .build[Integer, DataObject]((key => loader(key)): CacheLoader[Integer, DataObject])
    .enableCacheStatsReporting("deal-service", stats)
  }

如果您正在处理较旧的 Scala 版本,那么只需忘记 SAM 的存在并采用旧的方式即可。

def initCache(maximumSize: Int = 5): LoadingCache[Integer, DataObject] = {
  Caffeine
    .newBuilder()
    .maximumSize(maximumSize)
    .refreshAfterWrite(defaultCacheExpireDuration.length, defaultCacheExpireDuration.unit)
    .recordStats()
    .build[Int, DataObject](new CacheLoader[Integer, DataObject] {
      override def load(key: Integer): DataObject = loader(key)
    })
    .enableCacheStatsReporting("deal-service", stats)
  }