使用 sbt 构建的应用程序运行时出现 NoClassDefFoundError

Posted

技术标签:

【中文标题】使用 sbt 构建的应用程序运行时出现 NoClassDefFoundError【英文标题】:NoClassDefFoundError during runtime on application built with sbt 【发布时间】:2021-03-06 17:22:06 【问题描述】:

我有以下 build.sbt 文件:

lazy val shared = (project in file("shared")) .
  settings (moduleName := "x-shared") .
  ...

lazy val service = (project in file ("service")) .
  settings (moduleName := "x-api") .
  dependsOn (shared % "compile->compile;test->test", job % "compile->compile;test->test") .
  aggregate (shared, joob) .
  ...

lazy val job = (project in file("job") dependsOn (shared % "compile->compile;test->test")) .
  settings (moduleName := "x-job") .
  ...

服务子模块需要 sharedjob 模块。共享项目基本上是所有模块使用的一组类。作业和服务都是不同的应用程序,但我们在服务上有一个端点,需要启动作业应用程序。

问题在于,在运行时,我们在尝试引用 job 模块类时收到以下错误:

java.lang.NoClassDefFoundError: com/earnest/ingestor/models/Pipeline$

但是我们可以毫无问题地引用共享模块。

项目的文件夹结构如下:

./root
  ./service
  ./shared
  ./job

我注意到的一件事是,为 job 模块生成的 jar 文件不会被复制到 service 模块的 lib 文件夹中,这与 shared 不同jar文件:

service/target/universal/stage/lib 目录包含两者:

com.earnest.x-api-localdev.9288.jar
com.earnest.x-shared-localdev.9288.jar

但是 job jar 会填充到作业模块中:

job/target/universal/stage/lib 包含:

com.earnest.x-job-localdev.9288.jar

我对 sbt 构建还很陌生,所以不确定在构建过程中是否会丢失一些通过 sbt clean 命令完成的部分。我们正在使用 sbt-native-package 插件。我不确定还有哪些信息可能对分享有用,所以我提取了 build.sbt 关键点,提前感谢您的帮助。

sbt 插件:

addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.9.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.11")

更新 1

应用程序正在从一个launcher.jar 启动,它似乎是来自build.sbt 文件的LauncherJarPlugin。我注意到的一件事是launcher.jar 在META_INF/MANIFEST.MF 的ClassPath 中不包含com.earnest.x-job-localdev.9288.jar

【问题讨论】:

您使用了哪个构建命令? sbt-native-packager 通常不用于生产 uberjar。为此,通常使用sbt-assembly 我正在使用sbt clean <module> 命令,不确定它是如何配置的,但是这个命令正在构建完整的项目。我注意到的另一件事是应用程序是通过launcher.jar 运行的,我看到我们也在build.sbt 中使用LauncherJarPlugin,如果使用jar xf 命令提取,META_INF/MANIFEST.MF 不包括com.earnest.x-job-localdev.9288.jar 在类路径中。 如果没有有关配置的详细信息,我怀疑我们能够解决这个问题。 我应该只分享完整的 build.sbt 文件吗?我只是不想复制粘贴整个块。 复制粘贴任何与构建逻辑相关的内容。 【参考方案1】:

我能够通过添加 job % "compile->compile;test->test" 设置服务模块来解决我的问题

整个区块长这样:

lazy val service = (project in file ("service")) .
  settings (moduleName := "x-api") .
  dependsOn (shared % "compile->compile;test->test", job % "compile->compile;runtime->runtime;test->test") .
  aggregate (shared, job) .
  ...

【讨论】:

以上是关于使用 sbt 构建的应用程序运行时出现 NoClassDefFoundError的主要内容,如果未能解决你的问题,请参考以下文章

运行标量代码时出现Sbt抛出错误

尝试在 Intellij 中打开 sbt 项目时出现“sbt 启动器不存在”

解决 sbt 中的 jar 加载冲突

运行发布构建的应用程序时出现访问冲突异常

预测试 SBT 任务:无法实例化 JDBC 驱动程序

在 ionic 应用程序中安装预构建主题时出现运行时错误