Scala:如何跨应用程序使用全局配置案例类

Rak*_*esh 4 scala case-class

我是 Scala 的新手,刚开始使用我的第一个 Scala 应用程序。

我已经在资源文件夹 application.conf 下定义了我的配置文件

  projectname{
     "application" {
     "host":127.0.0.1
     "port":8080
    }
 }
Run Code Online (Sandbox Code Playgroud)

我写了一个配置解析器文件来从配置文件解析到案例类

    case class AppConfig (config: Config) {
      val host = config.getString("projectname.application.host")
      val port = config.getInt("projectname.application.port")
    }
Run Code Online (Sandbox Code Playgroud)

在我的 grpc 服务器文件中,我已将配置声明为

    val config = AppConfig(ConfigFactory.load("application.conf"))
Run Code Online (Sandbox Code Playgroud)

我想在整个应用程序中使用这个配置变量,而不是每次都加载 application.conf 文件。

我想要一个引导程序功能,它将解析此配置一次,使其在整个应用程序中可用

dvi*_*vir 5

您可以使用PureConfig自动执行此操作

build.sbt使用以下命令为您添加 Pure Config :

libraryDependencies += "com.github.pureconfig" %% "pureconfig" % "0.11.0"
Run Code Online (Sandbox Code Playgroud)

并重新加载 sbt shell 并更新您的依赖项。

现在,假设您有以下resource.conf文件:

host: example.com
port: 80
user: admin
password: admin_password
Run Code Online (Sandbox Code Playgroud)

您可以定义一个名为 的案例类AppConfig

host: example.com
port: 80
user: admin
password: admin_password
Run Code Online (Sandbox Code Playgroud)

并使用以下loadConfig方法创建它的一个实例,填充应用程序配置:

case class AppConfig(
    host: String,
    port: Int,
    user: String,
    password: String
)
Run Code Online (Sandbox Code Playgroud)

这将返回错误或您的 AppConfig,具体取决于配置本身的值。
例如,如果port上面的值是eighty,而不是 80,你会得到一个详细的错误,说第二个配置行(带有port: eighty)包含一个字符串,但唯一有效的预期类型是一个数字:

ConfigReaderFailures(
    ConvertFailure(
        reason = WrongType(
        foundType = STRING,
        expectedTypes = Set(NUMBER)
    ),
    location = Some(
        ConfigValueLocation(
           new URL("file:~/repos/example-project/target/scala-2.12/classes/application.conf"),
           lineNumber = 2
        )
    ),
    path = "port"
    )
)

Run Code Online (Sandbox Code Playgroud)

loadConfigOrThrow如果你想得到AppConfig而不是一个,你可以使用。

在应用程序开始时(尽可能接近主函数)加载此配置后,您可以使用依赖注入将其传递给所有其他类,只需在构造函数中传递 AppConfig 即可。

如果您想使用MacWire将您的 Logic 类(和其他服务)与配置案例类连接起来,正如 Krzysztof 在他的选项之一中建议的那样,您可以在此处查看我的答案。

简单的例子(没有MacWire),看起来像这样:

import pureconfig.generic.auto._

val errorsOrConfig: Either[ConfigReaderFailures, AppConfig] = pureconfig.loadConfig[AppConfig]
Run Code Online (Sandbox Code Playgroud)

其中 AppConfig 定义在 AppConfig.scala

ConfigReaderFailures(
    ConvertFailure(
        reason = WrongType(
        foundType = STRING,
        expectedTypes = Set(NUMBER)
    ),
    location = Some(
        ConfigValueLocation(
           new URL("file:~/repos/example-project/target/scala-2.12/classes/application.conf"),
           lineNumber = 2
        )
    ),
    path = "port"
    )
)

Run Code Online (Sandbox Code Playgroud)

作为奖励,当您在 IDE 中使用此配置变量时,您将获得代码完成。

此外,您的配置可以从支持的类型构建,例如 String、Boolean、Int 等,但也可以从从支持的类型构建的其他案例类(这是因为案例类表示一个值对象,其中包含数据),以及支持类型的列表和选项。
这允许您“分类”一个复杂的配置文件并获得代码完成。例如,在application.conf

name: hotels_best_dishes
host: "https://example.com"
port: 80
hotels: [
  "Club Hotel Lutraky Greece",
  "Four Seasons",
  "Ritz",
  "Waldorf Astoria"
]
min-duration: 2 days
currency-by-location {
  us = usd
  england = gbp
  il = nis
}
accepted-currency: [usd, gbp, nis]
application-id: 00112233-4455-6677-8899-aabbccddeeff
ssh-directory: /home/whoever/.ssh
developer: {
  name: alice,
  age: 20
}
Run Code Online (Sandbox Code Playgroud)

然后在您的代码中定义一个配置案例类:

package com.example

import com.example.config.AppConfig

object HelloWorld extends App {
 val config: AppConfig = pureconfig.loadConfigOrThrow[AppConfig]
 val logic = new Logic(config)
}

class Logic(config: AppConfig) {
   // do something with config
}
Run Code Online (Sandbox Code Playgroud)

并加载它:

package com.example.config

case class AppConfig(
    host: String,
    port: Int,
    user: String,
    password: String
)
Run Code Online (Sandbox Code Playgroud)