在 SBT 中为模块依赖使用自定义 class 加载器
Using a custom class loader for a module dependency in SBT
我有一个由 api
、core
和 third-party
组成的多模块 SBT 构建。结构大致是这样的:
api
|- core
|- third-party
third-party
的代码实现了 api
并且是从其他地方逐字复制的,所以我真的不想碰它。
由于 third-party
的实现方式(大量使用单例),我不能只让 core
依赖于 third-party
。具体来说,我只需要通过 api
使用它,但我需要在运行时拥有 third-party
的多个独立副本。 (这允许我同时拥有多个 "singletons"。)
如果我 运行 在我的 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()
}
但问题是,如果我是 运行 通过 sbt core/run
,我不知道如何在运行时弄清楚我应该给 URLClassLoader
什么作为参数。
这应该可行,尽管我没有用您的设置对其进行完全测试。
基本思路是让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 和依赖项目)或任何其他与类路径相关的键。
我有一个由 api
、core
和 third-party
组成的多模块 SBT 构建。结构大致是这样的:
api
|- core
|- third-party
third-party
的代码实现了 api
并且是从其他地方逐字复制的,所以我真的不想碰它。
由于 third-party
的实现方式(大量使用单例),我不能只让 core
依赖于 third-party
。具体来说,我只需要通过 api
使用它,但我需要在运行时拥有 third-party
的多个独立副本。 (这允许我同时拥有多个 "singletons"。)
如果我 运行 在我的 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()
}
但问题是,如果我是 运行 通过 sbt core/run
,我不知道如何在运行时弄清楚我应该给 URLClassLoader
什么作为参数。
这应该可行,尽管我没有用您的设置对其进行完全测试。
基本思路是让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 和依赖项目)或任何其他与类路径相关的键。