在 uber jar 中构建 sbt 项目,而不是单独的子模块 jar

Posted

技术标签:

【中文标题】在 uber jar 中构建 sbt 项目,而不是单独的子模块 jar【英文标题】:Build sbt project in uber jar instead of individual submodule jars 【发布时间】:2021-01-22 11:13:30 【问题描述】:

最近一直在尝试改变我的 Scala 项目进行组装的方式,以便只生成一个 jar,而不是每个模块一个。

main-project
| - inner-module-one [inner_module_one]
| - inner-module-two [inner_module_two]

我目前对主模块(我希望它的 uber jar 包含其他模块内容的那个)进行了以下操作。

project
  .in(file("."))
  .settings(
    name := "main-project",
    assemblyName,
    settings
  )
  .aggregate(
    inner_module_one,
    inner_module_two
  )

另外两个模块声明如下。

lazy val inner_module_one = project
  .in(file("inner-module-one"))
  .settings(
    name := "inner-module-one",
    assemblyName,
    settings,
    dependencies and such (...)
  )
  .dependsOn(
    inner_module_two
  )

main-project 生成的 jar 文件非常非常小(大小不超过 5mbs),并且只包含 Scala 相关的内容,没有项目类等。但是,其他模块的 jar 包是完整的,并且包含了它们所需的一切。

我已经尝试将以下设置添加到main-project

aggregate in assembly := false

但到目前为止仍然没有运气。没有生成子模块的 jar,但 main-project jar 仍然不包含子模块的内容。

任何线索可能是问题所在?

编辑

尝试了@LuisMiguelMejíaSuárez 的建议并且似乎想要构建,但是出现了一些已经在各自模块中解决的错误。在给定的模块中,由于某些覆盖而解决了一些冲突,但现在它们又出现了。

[error] deduplicate: different file contents found in the following:

使用dependsOn 而不是aggregate 会影响添加、覆盖等依赖项的方式?

【问题讨论】:

也许使用dependsOn 而不是aggregate 可以解决问题? 它确实有效!有点......在一个模块中解决的依赖问题现在在更改为dependsOn后重复......主模块是否应该包含与其子模块相同的依赖关系和着色规则? @LuisMiguelMejíaSuárez 和错误我的意思是这种错误 [error] deduplicate: different file contents found in the following: 是的,不知道,对不起。我从来没有这样做过,只是认为这可能会有所帮助。您可能还想在gitter channel 中提问。 【参考方案1】:

让我们把你的问题分成两部分,如何将子模块包含到main-project中,你想知道如何不打包组装这2个子模块。

让我们从更简单的第二个开始。 sbt-assembly,是 sbt 的插件。就像任何其他插件一样,您不能使用 disablePlugins 命令禁用它。因此,如果你定义:

lazy val inner_module_one = project.disablePlugins(AssemblyPlugin)
  .in(file("inner-module-one"))
  .settings(
    name := "inner-module-one"
)
.dependsOn(
  inner_module_two
)

那么 inner_module_one 就不会构建一个 jar。

要解决第一个问题,我们需要了解aggregate和dependsOn的区别。为此,我将引用Jacek Laskowski great explanation:

aggregate 导致任务在聚合模块中执行,并且所有任务都被聚合,而dependsOn 设置了一个 CLASSPATH 依赖项,因此这些库对聚合模块是可见的(取决于示例中的默认编译配置)。

因此,当您聚合 inner_module_oneinner_module_two 时,您也将导致它们也进行组装。为了让这些成为main-project 的一部分,您需要做的就是声明:

project
  .in(file("."))
  .settings(
    name := "main-project",
    assemblyName,
    settings
  )
  .dependsOn(
    inner_module_one,
    inner_module_two
  )

为了测试它,我创建了以下结构:

main-project
|-inner_module_one
 |-main
  |-scala
   |One.scala
|-inner_module_two
 |-main
  |-scala
   |Two.scala

为了检查类 One 是否在 jar 中,我使用了以下命令:

jar tfv inner-module-one/target/scala-2.12/inner-module-one-assembly-0.1.0-SNAPSHOT.jar | grep One 

然后,当使用原始 aggregate 运行 sbt assembly 时,上面的命令在输出 jar 上提供了空结果。当运行sbt assemblydependsOn 时,上面的命令提供了一个结果:

480 Fri Oct 09 01:48:14 IDT 2020 One.class

如果这会导致冲突,您可以在 sbt-assembly: deduplication found error 阅读相关内容

【讨论】:

那再清楚不过了!非常感谢 Tomer 的回复。

以上是关于在 uber jar 中构建 sbt 项目,而不是单独的子模块 jar的主要内容,如果未能解决你的问题,请参考以下文章

sbt-assembly 多模块项目?

如何使用 sbt-assembly 和 sbt-native-packager 构建 deb 包以包含单个程序集 jar?

解决 sbt 中的 jar 加载冲突

使用 scala sbt 构建一个独立的 jar 以合并到一个 android 项目中

Spark如何从打包的jar中选择类

使用 sbt-assembly 来自单个项目的具有不同外部依赖项的多个可执行 jar 文件