简述

HOCON(Human-Optimized Config Object Notation)是一个易于使用的配置文件格式,具有面向对象风格。

akka的配置文件就是用的conf格式

该篇演示使用方式

解析库

1
2
3
4
5
<dependency>
    <groupId>com.typesafe</groupId>
    <artifactId>config</artifactId>
    <version>1.4.0</version>
</dependency>

使用演示

样例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
akka {
  loggers = ["akka.event.slf4j.Slf4jLogger"]
  loglevel = "DEBUG"
  actor {
    provider = "cluster"
    default-dispatcher {
      throughput = 10
    }
  }

  remote {
    netty.tcp{
      port = 4711
    }
  }
}

akka使用的配置

ConfigFactory 支持解析 conf、json、properties格式的配置文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  def case01 {
    val sysName = "dizangwang"
    // 默认加载application.*
    // resources目录下放 application.conf、 application.json、 application.properties 任意一个都行
    val config: Config = ConfigFactory.load()
    // 二者效果相同
    val system01: ActorSystem = ActorSystem.create(sysName)
    val system02: ActorSystem = ActorSystem.create(sysName, config)
    val system03: ActorSystem = ActorSystem.create(sysName, ConfigFactory.load("application.conf"))
  }

待解析配置文件

1
2
3
4
5
6
7
resources
├── application.conf
└── usecfg
    ├── app-01.conf
    ├── app-02.conf
    ├── app-03.json
    └── app-04.properties

app-01.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
akka {
  loggers = ["akka.event.slf4j.Slf4jLogger"]
  loglevel = "DEBUG"
  actor {
    provider = "cluster"
    default-dispatcher {
      throughput = 10
    }
  }

  remote {
    netty.tcp{
      port = 4711
    }
  }
}

app-02.conf

1
2
3
4
5
6
7
8
9
app1{
  akka {
    loglevel = "DEBUG"
  }
}

app2.akka {
  loglevel = "DEBUG"
}

app-03.conf

1
2
3
{
  "akka": {"loglevel" : "DEBUG"}
}

app-04.properties

1
2
app1.akka.loglevel=DEBUG
app2.akka.loglevel=DEBUG

代码解析

对于3种配置文件格式的支持

1
2
3
4
val cfg01: Config = ConfigFactory.load("usecfg/app-01.conf")
val cfg02: Config = ConfigFactory.load("usecfg/app-02.conf")
val cfg03: Config = ConfigFactory.load("usecfg/app-03.json")
val cfg04: Config = ConfigFactory.load("usecfg/app-04.properties")

配置信息的读取

1
2
3
4
5
6
7
8
def case02() { // 效果相同
  assert("DEBUG" equals cfg01.getString("akka.loglevel"))
  assert("DEBUG" equals cfg02.getString("app1.akka.loglevel"))
  assert("DEBUG" equals cfg02.getString("app2.akka.loglevel"))
  assert("DEBUG" equals cfg03.getString("akka.loglevel"))
  assert("DEBUG" equals cfg04.getString("app1.akka.loglevel"))
  assert("DEBUG" equals cfg04.getString("app2.akka.loglevel"))
}

默认加载位置可覆盖

1
2
3
4
5
6
7
8
def case03() { // 效果相同
  println("通过启动参数覆盖默认加载位置")
  // ConfigFactory.load() 默认是找classpath*:application.conf 文件
  // jvm启动时的附加参数可以调整默认位置 -Dconfig.resource=xx, -Dconfig.file=xx, -Dconfig.url=xx
  System.setProperty("config.resource", "usecfg/app-03.json")
  val cfg0003: Config = ConfigFactory.load()
  assert("DEBUG" equals cfg0003.getString("akka.loglevel"))
}

还可从其他方式加载配置

从字符串解析、 从文件加载、 从url加载

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  var config: Config = null;
  val cs01 =
    """
      |app1{
      |  akka {
      |    loglevel = "DEBUG"
      |  }
      |}
      |""".stripMargin
  val cs02 =
    """
      |{
      |  "akka": {"loglevel" : "DEBUG"}
      |}
      |
      |""".stripMargin

  println("解析字符串的方式装载配置 -- 可从多种来源加载[ .parseString .parseFile .parseURL ...more ]")
  val cfg01: Config = ConfigFactory.parseString(cs01)
  val cfg02: Config = ConfigFactory.parseString(cs02)

  println(cfg02.getString("akka.loglevel"))
  assert(cfg01.getString("app1.akka.loglevel").equals(cfg02.getString("akka.loglevel")))

配置的合并、提取

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
val cs03 =
  """
    |db.a1.name=tom
    |db.a2.name=peter
    |log.zz=apple
    |""".stripMargin
val cfg03: Config = ConfigFactory.parseString(cs03)
// 值保留该路径的配置, 还剩一条记录
val xx: Config = cfg03.withOnlyPath("db.a2")
assert(xx.root().size() == 1)

// 只剔除该路径的配置, 还剩两条记录
val yy: Config = cfg03.withoutPath("db.a2")
assert(yy.root().size() == 2)

// 提取路径下的 config
config = cfg01.getConfig("app1")
assert(config.getString("akka.loglevel").equals("DEBUG"))

合并config

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
val cs04 =
  """
    |aa=11
    |bb=22
    |""".stripMargin
val cs05 =
  """
    |bb=2222
    |cc=33
    |""".stripMargin
val cfg04: Config = ConfigFactory.parseString(cs04)
val cfg05: Config = ConfigFactory.parseString(cs05)
// 二者合并, 有冲突则使用cfg08的值
config = cfg04.withFallback(cfg05)
assert(config.getString("bb").equals("22"))
assert(config.getString("cc").equals("33"))
println("done --")

more

1
2
3
4
5
6
7
ConfigFactory.defaultOverrides() // 仅加载了系统属性
ConfigFactory.defaultReference() // 所有路径下 reference.conf 的合并结果
ConfigFactory.defaultApplication() //  == defaultReference() + defaultOverrides()
ConfigFactory.load() // == defaultApplication() + resolve
ConfigFactory.systemEnvironment()
ConfigFactory.systemProperties() // 返回的是单例对象, 在清除缓存后,再调用可刷新
ConfigFactory.invalidateCaches() // 清除缓存, 加载的系统属性、环境变量都被缓存过