首页 > 解决方案 > 如何在“Scala”中为 Caffeine LoadingCache 编写缓存加载器以使“refreshAfterWrite”正常工作

问题描述

Scala 应用程序用例:

我们有一个基于 Scala 的模块,它从全局缓存(Redis)中读取数据并将其保存到本地缓存(Caffeine LoadingCache)中。由于我们希望这些数据异步刷新,我们使用 LoadingCache 并将 refreshAfterWrite 持续时间设置为 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$1: 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$1: 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 的新手,所以不确定我做错了什么;我尝试了这里这里提到的不同方法来编写加载程序,但没有任何效果(主要是在 Java 中)。围绕 Scala 边界的少量研究在这里没有任何帮助。请帮忙。

标签: scalacachingcaffeine-cache

解决方案


取决于这里使用的是哪个 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)
  }

推荐阅读