scala - 在 SBT 中为模块依赖项使用自定义类加载器

标签 scala sbt classloader

我有一个由 api 组成的多模块 SBT 版本, corethird-party .结构大致是这样的:

api
|- core
|- third-party
third-party 的代码实现 api并且是从其他地方逐字复制的,所以我真的不想碰它。

因为方式third-party已实现(大量使用单例),我不能只拥有 core取决于 third-party .具体来说,我只需要通过 api 使用它。 ,但我需要有多个独立的 third-party 副本在运行时。 (这允许我同时拥有多个“单例”。)

如果我在我的 SBT 构建之外运行,我只是这样做:
def createInstance(): foo.bar.API = {
  val loader = new java.net.URLClassLoader("path/to/third-party.jar", parent)
  loader.loadClass("foo.bar.Impl").asSubclass(classOf[foo.bar.API]).newInstance()
}

但问题是我不知道如何在运行时弄清楚我应该给 URLClassLoader 提供什么作为参数。如果我通过 sbt core/run 运行.

最佳答案

这应该可以工作,尽管我没有用你的设置完全测试它。

基本思想是让 sbt 将类路径写入一个文件
可以在运行时使用。 sbt-buildinfo
已经为此提供了很好的基础,所以我将在这里使用它,但是你
可能只提取相关部分而不使用此插件。

将此添加到您的项目定义中:

lazy val core = project enablePlugins BuildInfoPlugin settings (
  buildInfoKeys := Seq(BuildInfoKey.map(exportedProducts in (`third-party`, Runtime)) {
    case (_, classFiles) ⇒ ("thirdParty", classFiles.map(_.data.toURI.toURL)) 
  })
  ...

在运行时,使用这个:
def createInstance(): foo.bar.API = {
  val loader = new java.net.URLClassLoader(buildinfo.BuildInfo.thirdParty.toArray, parent)
  loader.loadClass("foo.bar.Impl").asSubclass(classOf[foo.bar.API]).newInstance()
}
exportedProducts仅包含项目的编译类(例如 .../target/scala-2.10/classes/ )。根据您的设置,您可能希望使用 fullClasspath反而
(其中还包含 libraryDependencies 和依赖项目)或任何其他与类路径相关的键。

关于scala - 在 SBT 中为模块依赖项使用自定义类加载器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29578808/

相关文章:

java.lang.NoClassDefFoundError : org/slf4j/impl/StaticLoggerBinder SBT Scala

java - 如何在 Java 中实现抽象单例类?

scala - 使用 sbt 加载 github 项目时发生 AttributeKeyID 冲突

scala - 基于 Scala 数组过滤或标记行

scala - 在 Scala 中创建和传递包含多种类型的字典的最佳方法是什么?

scala - giter8 抛出 IllegalArgumentException : Invalid wildcards +refs/pull/*/head:refs/rem otes/origin/pr/*

scala - 如何在编译任务之前执行shell命令?

java - 如何捕获静态初始化程序 block 中抛出的异常

java - 使用类加载器在 java 程序中运行可执行 jar 文件

scala - 无法覆盖 Spark 2.x 中 CSV 文件的架构