scala - 如何确保只有一个 Akka JAR 出现在类路径上?

标签 scala sbt akka

我遇到了akka.ConfigurationException:Akka JAR版本[2.1.0]与提供的配置版本[2.2.3]不匹配。我的猜测是,不知何故,$SCALA_HOME/lib/akka-actors.jar 正在与 SBT 管理的 Akka JAR 一起进入类路径。

我创建了一个简单的独立 SBT 项目来演示该问题(见下文)。我的 $SCALA_HOME 指向 Scala 2.10.3。在 Build.scala 中,我明确将 scalaHome 设置为 $SCALA_HOME

project/Build.scala

import sbt._
import sbt.Keys._

object ApplicationBuild extends Build {
  val appName     = "akka-version-problem"
  val appVersion  = "0.1-SNAPSHOT"

  val getJars = TaskKey[Unit]("get-jars")
  val getJarsTask = getJars <<= (target, fullClasspath in Compile) map { (target, cp) =>
    println(cp map { _.data } filter { _.getAbsolutePath.contains("lib") } mkString "\n")
    println(cp map { _.data } filter { _.getAbsolutePath.contains("akka") } mkString "\n")
  }

  lazy val root = Project("root", file(".")).settings(
    scalaVersion := "2.10.3",

    scalaHome := Some(file(System.getenv("SCALA_HOME"))),

    autoScalaLibrary := false,

    libraryDependencies ++= Seq(
      "com.typesafe.akka" %% "akka-actor" % "2.2.3"
    ),

    getJarsTask
  )
}

src/main/scala/com/example/Main.scala

package com.example

import akka.actor.ActorSystem

object Main extends App {
  val system = ActorSystem("AkkaDemoSystem")
  system.shutdown()
}

当我运行 sbt get-jars 时,我在输出中没有看到 $SCALA_HOME/lib/akka-actors.jar 当我运行 sbt run 时,我得到:

[error] (run-main) 44c2d48a-8899-43f9-804b-55cbf739b08bakka.ConfigurationException: Akka JAR version [2.1.0] does not match the provided config version [2.2.3]
44c2d48a-8899-43f9-804b-55cbf739b08bakka.ConfigurationException: Akka JAR version [2.1.0] does not match the provided config version [2.2.3]
    at akka.actor.ActorSystem$Settings.<init>(ActorSystem.scala:172)
    at akka.actor.ActorSystemImpl.<init>(ActorSystem.scala:465)
    at akka.actor.ActorSystem$.apply(ActorSystem.scala:111)
    at akka.actor.ActorSystem$.apply(ActorSystem.scala:93)
    at com.example.Main$delayedInit$body.apply(Main.scala:6)
    at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
    at scala.App$$anonfun$main$1.apply(App.scala:71)
    at scala.App$$anonfun$main$1.apply(App.scala:71)
    at scala.collection.immutable.List.foreach(List.scala:318)
    at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)
    at scala.App$class.main(App.scala:71)
    at com.example.Main$.main(Main.scala:5)
    at com.example.Main.main(Main.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)

我是否遗漏了一些明显的东西?还有其他人遇到过这种情况吗?

最佳答案

这里的问题是 akka-actors.jar 是 scala 发行版的一部分。默认情况下,Sbt 在类路径中包含所有这些 jar。所以,您最终会得到 scala 发行版中的 Akka 版本您直接依赖的版本。

不仅如此,您还包括 scala-actors、scala-reflect 等。如果这是您想要的,那就太好了。

如果您想防止自己使用比您想要的更多的 jar,您应该直接创建您使用的 scalaInstance。请参阅http://www.scala-sbt.org/release/api/index.html#sbt.ScalaInstance $ 用于构造方法(您可以看到其中之一使用 scalaHome)。

我建议这样做(注意:sbt 0.13 代码):

scalaInstance := {
    val homeDir = file("/path/to/scala-home")
    val jars = (homeDir ** ".jar").get
    val notAkka = jars filterNot (_ contains "akka")
    val scalaLib = ScalaInstance.scalaJar(homeDir, "scala-library.jar")
    val compilerLib = ScalaInstance.scalaJar(homeDir, "scala-compiler.jar")
    ScalaInstance(scalaLib, compilerLib, notAkka:_*)(state.classLoaderCache.apply _)
}

这会向您发出已弃用的警告。这是因为我们假设如果您使用 scalaHome,您想要来自 scala 的所有默认模块。由于情况并非如此,您可以忽略它。

正如 Viktor 所说,我建议仅使用 sbt 的 Scala 解析机制。如果您这样做,则默认情况下会完成类加载器的缓存,并且它只会下载一次工件。现实情况是,sbt 无论如何都必须下载一个版本的 scala 来编译您的构建,然后它才会知道您已经为项目配置了 scalaHome(因为您使用 scala 本身指定了这一点)。

希望有帮助!

关于scala - 如何确保只有一个 Akka JAR 出现在类路径上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19594157/

相关文章:

java - 使用最新版本的 Scala 会出现 java.lang.ClassNotFoundException : scala. Function1$class

sbt - 如何使用 sbt-release 插件实现独立的多模块版本控制

scala - spark-csv 包中的 inferSchema

scala - 在 Scala 中检查 Java 数据类型的空值

unit-testing - SBT 中的基本测试功能

scala - 具有持久参与者的 Akka 分片的背压

playframework - 超时后中断 Play 2 中的长时间计算

java - 是否可以从 ActorSelection 中检索多个 actorRef?

scala - 用一个枚举器提供两个迭代器

java - 从继承的 protected Java 字段创建公共(public)访问器