我有一个由 api
组成的多模块 SBT 版本, core
和 third-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/