实现重新加载Typesafe配置的好方法是什么

rei*_*kje 10 java scala concurrentmodification typesafe-config

在使用Typesafe Config的Scala应用程序中,我想添加在运行时重新加载Config的可能性.Config实例是不可变的.这是我到目前为止:

package config

trait Settings {
  private[config] var config: Config = ConfigFactory.empty()
  def engine: EngineSettings
}

trait EngineSettings {
  def weight: Int
  def offset: Int
}

class AppSettings {
  override def engine = new EngineSettings {
    override def weight = config.getInt("engine.weight")
    override def offset = config.getInt("engine.offset")
  }
}

object Settings {
  private val namedSettings = new TrieMap[String, AppSettings]
  def load(configName: String = "local"): Settings = {
    // load config
    // create or update AppSettings
    // add to map and return
  }
}
Run Code Online (Sandbox Code Playgroud)

最初使用Settings.load创建Settings实例.该实例引用将传递给其他类.然后第二个线程可以通过再次调用Settings.load来重新加载底层配置.以下是您访问它的方式:

class Engine(settings: Settings) {
  def calculate() = {
    val weight = settings.engine.weight
    // do some stuff
    val offset = settings.engine.offset
  }
}
Run Code Online (Sandbox Code Playgroud)

有两个问题:

  1. 有人可能会重新加载底层配置,而calculate()是在行://做一些东西(一致性)
  2. 不喜欢在设置特征中使用var

我怎样才能改进这个设计:)

cir*_*ter 4

您可以转变config为支持配置缓存失效(并具有合理的默认值)的方法,以便您可以在动态(以下示例中的默认值)和性能之间进行选择。

一般来说,我建议您使用 TypeSafe Config 的良好 Scala 类型安全包装器,例如 Ficus(例如 Gradle-stype 工件依赖项net.ceedubs:ficus_2.11:1.1.1

package config

import scala.collection.concurrent.TrieMap

import com.typesafe.config.{Config, ConfigFactory}
import net.ceedubs.ficus.Ficus._

trait Settings {
  protected[config] def config (
    name: String = "local",
    invalidateCache: Boolean = false
  ): Config = {
    if (invalidateCache) { ConfigFactory invalidateCaches }
    ConfigFactory load name
  }
  def engine: EngineSettings
}

trait EngineSettings {
  def weight: Int
  def offset: Int
}

class AppSettings(val name: String = "local") extends Settings {
  val c = config()

  override def engine = new EngineSettings {
    override def weight = c.as[Int]("engine.weight")
    override def offset = c.as[Int]("engine.offset")
  }
}

object Settings {
  private val namedSettings = new TrieMap[String, AppSettings]
  def load(configName: String = "local"): Settings = {
    // e.g.
    val loadedUpToDate = new AppSettings
    namedSettings +=
      ((configName + "." + System.currentTimeMillis, loadedUpToDate))
    new Settings {
      override def engine = loadedUpToDate.engine
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我认为这可以解决您的问题,因为:

  1. 默认情况下,配置检索是通过重新加载动态进行的
  2. 通过使用一种方法,您不必求助于可变状态

  • https://github.com/typesafehub/config/issues/57对此问题有一些想法。我认为采取的一般方法是,您不希望引用一个配置(通过方法或其他任何方式)在读取不同值之间切换到另一个配置,因为这样配置可能会变得不一致。因此,这意味着有时需要获取一个全新的配置,然后重新创建依赖于它的所有内容。所以问题归结为“如何重新启动程序的配置部分” - 这就是为什么 Akka 不支持重新加载配置,因为它非常困难 (2认同)