1. 概述

Play 框架提供了一套简洁易用的 API 来管理应用的配置信息。掌握这些 API 是高效使用 Play 的第一步。

本文将带你了解如何在 Scala 项目中读取 Play 应用的配置数据。

2. Play 环境准备

我们使用最新版 Play 3.0.0 进行演示,不过大部分内容也适用于 Play 2.4 及以上版本。

创建一个新 Play 项目最简单的方式是使用 sbt 和官方提供的 giter8 模板 play-scala-seed.g8

sbt new playframework/play-scala-seed.g8

模板会提示输入项目名称和组织域名(用于包名命名空间),并自动生成一个基础的 Play 项目结构。

配置文件路径为:<项目名>/conf/application.conf

3. 配置文件格式

Play 的配置文件支持两种常见的写法:

3.1 类似 Java properties 的扁平结构:

player.name = "Player 1"
player.email = "[email protected]"
player.age = 18
player.twitterHandle = null
player.signUpDate = "2020-09-22T10:10:06"

3.2 类似 JSON 的嵌套结构:

player {
  name = "Player 1"
  email = "[email protected]"
  age = 18
  twitterHandle = null
  signUpDate = "2020-09-22T10:10:06"
}

这两种方式效果一致。

3.3 覆盖配置项 ✅

配置中允许重复定义同一个 key,后出现的值会覆盖前面的。我们可以利用这个特性从环境变量中加载配置值:

myApp.apiKey= null
myApp.apiKey= ${?MYAPP_APIKEY}

这里我们设定了默认值为 null,但如果设置了环境变量 MYAPP_APIKEY,它就会被优先使用。这对于容器化部署(如 Docker)非常友好。

4. 主要 Scala API

从 Play 2.4 开始,推荐通过依赖注入的方式获取 play.api.Configuration 实例来访问配置:

class MyService @Inject() (configuration: Configuration) {
  val name = configuration.get[String]("myApp.user.name")
  val email = configuration.get[String]("myApp.user.email")
}

最常用的 API 是:

Configuration.get[T](path: String)(implicit loader: ConfigLoader[T]): T

⚠️ 注意:可以使用 Option[T] 包裹类型来避免异常抛出:

class MyService @Inject() (configuration: Configuration) {
  val name = configuration.get[Option[String]]("myApp.user.name").getOrElse("Player1")
  val email = configuration.get[Option[String]]("myApp.user.email").getOrElse("[email protected]")
}

这种方式有两种常见用途:

  1. 设置默认值(⚠️ 不推荐滥用,容易导致多层覆盖时行为不可控)
  2. 自定义缺失配置时的错误处理逻辑(比如抛出自定义异常)

📌 ConfigLoader 是关键组件:它负责把配置中的字符串转换成具体的 Scala 类型。Play 内置了对 StringIntBooleanSeqDuration 等常用类型的自动转换支持。

5. 自定义数据类型映射

借助 ConfigLoader,我们可以轻松将配置映射到自定义类。

以之前的 player 配置为例:

5.1 定义 case class

case class PlayerInfo(
    name: String,
    email: String,
    age: Int,
    signUpDate: Date,
    twitterHandle: Option[String] = None
)

5.2 编写 ConfigLoader

object PlayerInfo {
  implicit val playerInfoConfigLoader: ConfigLoader[PlayerInfo] =
    (rootConfig: Config, path: String) => {
      val config = rootConfig.getConfig(path)
      new PlayerInfo(
        config.getString("name"),
        config.getString("email"),
        config.getInt("age"),
        javax.xml.bind.DatatypeConverter
          .parseDateTime(config.getString("signUpDate"))
          .getTime,
        Try(config.getString("twitterHandle")).toOption
      )
    }
}

5.3 使用方式

val playerInfo: PlayerInfo = configuration.get[PlayerInfo]("player")

虽然看起来有点复杂,但如果需要复用配置结构,这种做法非常实用。

6. 小结

本文介绍了 Play 框架中如何读取和使用配置数据。无论是基本类型还是自定义对象,Play 都提供了优雅的支持。

完整代码示例可以在 GitHub 仓库 找到。


原始标题:Access Play Configuration in Scala