我正在尝试在为我的SBT构建编写的任务中运行一个相当简单的HTTP POST请求,并且看到SBT似乎没有帮助,我决定使用spray-client来完成此任务。 / p>
在project/dependencies.sbt
文件中,我提出以下内容:
resolvers += "spray.io repo" at "http://repo.spray.io/"
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % "2.2.3",
"io.spray" % "spray-client" % "1.2.0")
我的任务是通过以下方式实现的:
def uploadSite(version: String, siteArchive: File, log: Logger): HttpResponse = {
def request: HttpRequest = Post(siteUploadUrl,
MultipartFormData(Map(
// abridged
))
implicit val system = ActorSystem() // <-- Exception HERE!
try {
import system.dispatcher
val future: Future[HttpResponse] = pipelining.sendReceive(request)
Await.result(future, 1 minute)
}
finally system.shutdown()
}
当我运行以下异常时,任务失败:
com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'akka'
at com.typesafe.config.impl.SimpleConfig.findKey(SimpleConfig.java:115)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:138)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:150)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:155)
at com.typesafe.config.impl.SimpleConfig.getString(SimpleConfig.java:197)
at akka.actor.ActorSystem$Settings.<init>(ActorSystem.scala:136)
at akka.actor.ActorSystemImpl.<init>(ActorSystem.scala:470)
at akka.actor.ActorSystem$.apply(ActorSystem.scala:111)
at akka.actor.ActorSystem$.apply(ActorSystem.scala:93)
at akka.actor.ActorSystem$.apply(ActorSystem.scala:82)
at MyIO$.uploadSite(MyIO.scala:65)
我的基本分析是,reference.conf
中找不到的akka-actor_2.10-2.2.3.jar
文件没有被读取,因为某些原因让我感到厌烦,并且可能与SBT如何管理其类路径以运行建立。
一些精确性:我在SBT 0.13.0上(因此构建代码为Scala 2.10)并且我检查了前面提到的akka-actor jar确实包含一个reference.conf文件,这是预期的。在查看我 guess 可能与构建执行类路径(reload plugins
然后在{s}中的show runtime:fullClasspath
)相关时,该jar会出现在列表中。
我也没有通过谷歌搜索相关的任何内容,无法表达问题在于从SBT构建中的运行akka 。
最后,我真的不知道'akka'配置密钥是如何丢失的。有人可以帮忙吗?
答案 0 :(得分:4)
关于akka真正讨厌的事情是你需要为泛型设置更新线程本地上下文类加载器,而很多工具(比如sbt)都没有,因为他们不知道你在运行什么线程或者你需要哪个类加载器。
这是an example from the activator build:
val cl = ??? // Some mechanism of getting Akka's classpath with your classes too
val old = Thread.currentThread.getContextClassLoader
Thread.currentThread.setContextClassLoader(cl)
try doSomethingWithAkka()
finally Thread.currentThread.setContextClassLoader(old)
编辑(通过OP),以便比评论中更明显:
Akka(自2.0开始)选择它在ActorSystem中使用的类加载器(当它不作为参数传递时)通过选择第一个可用(和非空):
Thread.currentThread.getContextClassLoader
getClassLoader
在调用堆栈上的非Akka堆栈框架类ActorSystem.getClass.getClassLoader
这就是上述变异上下文类加载器的解决方案的原因。
对于在实践中使用的类加载器,我得到了val cl = getClass.getClassLoader
(来自我的构建定义类)的预期行为,因为该类加载器包含所有构建定义,插件和依赖项。它也有效地使上面的步骤1表现得像第2步。
最后,我通过调用ActorSystem("someName", ConfigFactory.load(cl), cl)
并且没有触及上下文类加载器来创建ActorSystem,这似乎更清晰(对于像我这样不知道是什么的人来说也不那么可怕)上下文类加载器是或确实)
TL; DR 而不是
val system = ActorSystem()
写
val cl = getClass.getClassLoader
val system = ActorSystem("mySystem", ConfigFactory.load(cl), cl)