配置

你可以在不定义任何配置的情况下使用Akka,这是因为Akka提供了合适的默认值。你可能需要修设置从而改变默认的行为或者适应一个特定的运行时环境。你可能需要改变的设置有如下几点:

  • 日志等级和日志备份
  • 开启远程访问功能
  • 消息序列化
  • 定义路由器
  • 调度器调优

Akka 使用Typesafe Config库, 不管使用或不使用Akka也可以使用它来配置你自己的项目。这个库是用java写的,没有外部依赖;你最好看看它的文档 (特别是ConfigFactory), 以下内容是对这个文档的概括。

配置数据从哪里来?

Akka的所有配置信息装在ActorSystem的实例中, 或者换个说法, 从外界看来, ActorSystem是配置信息的唯一消费者. 在构造一个actor系统时,你可以传进来一个Config object,如果不传,就相当于传进来ConfigFactory.load() (使用正确的classloader)。这意味着将会读取classpath根目录下的所有application.conf, application.jsonapplication.properties这些文件。 然后actor系统会合并classpath根目录下的reference.conf来组成其内部使用的缺省配置。

  1. appConfig.withFallback(ConfigFactory.defaultReference(classLoader))

其中的奥妙是代码不包含缺省值,而是依赖于随库提供的reference.conf中的配置。

系统属性中覆盖的配置具有最高优先级,见HOCON 规范 (靠近末尾的位置). 要提醒的是应用配置—缺省为 application—可以使用config.resource中的属性来覆盖。

注意:

如果你编写的是一个Akka应用,把配置放在classpath根目录下的application.conf 中。如果你编写的是一个基于Akka的库,把配置放在jar包根目录下的reference.conf中。

自定义application.conf

一个自定义的application.conf可能如下所示:

  1. // In this file you can override any option defined in the reference files.
  2. // Copy in parts of the reference files and modify as you please.
  3. akka {
  4. // Loggers to register at boot time (akka.event.Logging$DefaultLogger logs
  5. // to STDOUT)
  6. loggers = ["akka.event.slf4j.Slf4jLogger"]
  7. // Log level used by the configured loggers (see "loggers") as soon
  8. // as they have been started; before that, see "stdout-loglevel"
  9. // Options: OFF, ERROR, WARNING, INFO, DEBUG
  10. loglevel = "DEBUG"
  11. // Log level for the very basic logger activated during ActorSystem startup.
  12. // This logger prints the log messages to stdout (System.out).
  13. // Options: OFF, ERROR, WARNING, INFO, DEBUG
  14. stdout-loglevel = "DEBUG"
  15. actor {
  16. provider = "akka.cluster.ClusterActorRefProvider"
  17. default-dispatcher {
  18. // Throughput for default Dispatcher, set to 1 for as fair as possible
  19. throughput = 10
  20. } }
  21. remote {
  22. // The port clients should connect to. Default is 2552.
  23. netty.tcp.port = 4711
  24. } }

包含文件

有时候我们需要包含其它配置文件,例如你有一个 application.conf 定义所有与依赖环境的设置,然后在具体的环境中对其中的设置进行覆盖。

通过-Dconfig.resource=/dev.conf指定系统属性将会加载dev.conf文件,这个文件包含application.conf

  1. include "application"
  2. akka {
  3. loglevel = "DEBUG"
  4. }

更高级的包含和替换机制在HOCON规范中有解释

配置日志

如果系统属性或配置属性akka.log-config-on-start设置为on, 那么当actor系统启动时整个配置的日志级别为INFO. 这在你不确定使用哪个配置时会有用。

如果有疑问,你也可以在用它们构造一个actor系统之前或之后很方便地了解配置对象的内容:

  1. Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_27).
  2. Type in expressions to have them evaluated.
  3. Type :help for more information.
  4. scala> import com.typesafe.config._
  5. import com.typesafe.config._
  6. scala> ConfigFactory.parseString("a.b=12")
  7. res0: com.typesafe.config.Config = Config(SimpleConfigObject({"a" : {"b" : 12}}))
  8. scala> res0.root.render
  9. res1: java.lang.String =
  10. {
  11. # String: 1
  12. "a" : {
  13. # String: 1
  14. "b" : 12 }
  15. }

每一条设置之前的注释给出了原有设置的详情信息 (文件和行号) 以及(在参考配置中)可能出现的注释,与参考配置合并并被actor系统解析的设置可以这样显示:

  1. final ActorSystem system = ActorSystem.create();
  2. System.out.println(system.settings());
  3. // this is a shortcut for system.settings().config().root().render()

关于类加载器

在配置文件的某些地方可以指定要被Akka实例化的类的全路径。这是通过Java反射来实现的,会用到类加载器。在应用窗口或OSBi包里正确地使用它并不总是容易的事,目前Akka采取的方式是每个ActorSystem实现存有当前线程的上下文类加载器 (如果有的话,否则使用this.getClass.getClassLoader的返回值) 并用它来进行所有的反射操作。这意味着把Akka放到启动类路径中会在一些莫名其妙的地方造成NullPointerException:这是不被支持的。

配置多个ActorSystem

如果你有超过一个ActorSystem,你可能为每个系统分开进行配置。

由于 ConfigFactory.load() 会合并classpath中所有匹配名称的资源, 最简单的方式是利用这一功能在配置树中区分actor系统:

  1. myapp1 {
  2. akka.loglevel = "WARNING"
  3. my.own.setting = 43
  4. }
  5. myapp2 {
  6. akka.loglevel = "ERROR"
  7. app2.setting = "appname"
  8. }
  9. my.own.setting = 42
  10. my.other.setting = "hello"
  1. val config = ConfigFactory.load()
  2. val app1 = ActorSystem("MyApp1", config.getConfig("myapp1").withFallback(config))
  3. val app2 = ActorSystem("MyApp2",config.getConfig("myapp2").withOnlyPath("akka").withFallback(config))

这两个例子演示了“提升子树”(lift-a-subtree)技巧的不同变种: 第一种中,actor system获得的配置是

  1. akka.loglevel = "WARNING"
  2. my.own.setting = 43
  3. my.other.setting = "hello"
  4. // plus myapp1 and myapp2 subtrees

而在第二种中,只有 “akka” 子树被提升了,结果如下:

  1. akka.loglevel = "ERROR"
  2. my.own.setting = 42
  3. my.other.setting = "hello"
  4. // plus myapp1 and myapp2 subtrees

注意:这个配置文件库非常强大,这里不可能解释所有的功能. 特别是如何在配置文件中引用其它的配置文件 (例子见 包含文件) 和通过路径替换来复制部分配置信。

初始化ActorSystem时,你也可以通过代码来指定和处理配置信息。

  1. import akka.actor.ActorSystem
  2. import com.typesafe.config.ConfigFactory
  3. val customConf = ConfigFactory.parseString("""
  4. akka.actor.deployment {
  5. /my-service {
  6. router = round-robin
  7. nr-of-instances = 3
  8. }
  9. }
  10. """)
  11. // ConfigFactory.load sandwiches customConfig between default reference
  12. // config and default overrides, and then resolves it.
  13. val system = ActorSystem("MySystem", ConfigFactory.load(customConf))