get“找不到或加载主类”

mnowg1ta  于 2021-07-13  发布在  Spark
关注(0)|答案(2)|浏览(461)

我正在尝试创建一个可执行的.jar,其中包含一些提供的依赖项,我有一个从'gradle init'创建的简单示例,在添加几个提供的依赖项之前,我可以执行.jar,但是添加这些依赖项之后它就失败了。
我可以复制如下:

  1. mkdir /tmp/foo
  2. cd /tmp/foo
  3. run 'gradle init'
  4. Select type of project to generate:
  5. 2: application
  6. Select implementation language:
  7. 3: Java
  8. Select build script DSL:
  9. 1: Groovy
  10. Select test framework:
  11. 1: JUnit 4
  12. Project name (default: foo):
  13. Source package (default: foo):

然后在build.gradle的末尾添加以下内容:

  1. jar {
  2. manifest {
  3. attributes "Main-Class": "foo.App"
  4. }
  5. zip64 = true
  6. from {
  7. configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
  8. }
  9. }

在命令行中,运行:

  1. gradle clean ; gradle jar ; java -jar build/libs/foo.jar

你应该看到:

  1. Hello world.

现在将build.gradle中的“dependencies”块更改为:

  1. configurations {
  2. provided
  3. compile.extendsFrom(provided)
  4. }
  5. dependencies {
  6. implementation 'com.google.guava:guava:29.0-jre'
  7. testImplementation 'junit:junit:4.13'
  8. implementation "org.apache.spark:spark-sql_2.11:2.4.4"
  9. implementation "org.apache.spark:spark-hive_2.11:2.4.4"
  10. }

在命令行中,再次运行:

  1. gradle clean ; gradle jar ; java -jar build/libs/foo.jar

你应该看到一切都是好的:

  1. Hello world.

下一步,请更换

  1. implementation "org.apache.spark:spark-sql_2.11:2.4.4"
  2. implementation "org.apache.spark:spark-hive_2.11:2.4.4"

具有

  1. provided "org.apache.spark:spark-sql_2.11:2.4.4"
  2. provided "org.apache.spark:spark-hive_2.11:2.4.4"

在命令行中,再次运行:

  1. gradle clean ; gradle jar ; java -jar build/libs/foo.jar

这次您将获得:

  1. Error: Could not find or load main class foo.App

因此,这显然是由于试图使spark相关的依赖项“被提供”,因此不是.jar的一部分。但是,您会注意到foo.app类非常简单,与spark无关。所以,我现在很困惑,为什么在添加这些类型的依赖项时主类突然变得不可用。提前感谢您的帮助!

iovurdzv

iovurdzv1#

您可能自己也注意到了(这可能也是您想要的):构建的jar文件包含您使用时所有依赖jar的全部内容 provided (或 compile )而不是 implementationdependencies 阻止。
问题是你的 jar 任务配置实际上包含了依赖jar的所有内容,包括它们的 META-INF/ 目录文件。这些依赖jar中的一些似乎是经过签名的,因此在其内部包含数字签名 META-INF/ 目录–由您的 jar 任务也是。运行时 java -jar … ,这些签名会妨碍并导致类未找到错误(即使类在jar中)。
一个简单的解决方法是在创建jar文件时排除签名:

  1. jar {
  2. exclude 'META-INF/*.DSA'
  3. }

学分归这个所以回答。

tktrz96b

tktrz96b2#

下面是一个结合了chriki的解决方案和shadowjar方法的答案,shadowjar方法也对我有效。你挑吧!如果这篇文章对你有帮助,请投票给克里基。

  1. plugins {
  2. // Apply the java plugin to add support for Java
  3. id 'java'
  4. // Apply the application plugin to add support for building a CLI application.
  5. id 'application'
  6. // This was what I used in my solution
  7. id 'com.github.johnrengelman.shadow' version '5.2.0'
  8. }
  9. repositories {
  10. // Use jcenter for resolving dependencies.
  11. // You can declare any Maven/Ivy/file repository here.
  12. jcenter()
  13. }
  14. configurations {
  15. provided
  16. compile.extendsFrom(provided)
  17. }
  18. dependencies {
  19. implementation 'com.google.guava:guava:29.0-jre'
  20. testImplementation 'junit:junit:4.13'
  21. provided "org.apache.spark:spark-sql_2.11:2.4.4"
  22. provided "org.apache.spark:spark-hive_2.11:2.4.4"
  23. }
  24. application {
  25. // Define the main class for the application.
  26. mainClassName = 'foo.App'
  27. }
  28. test {
  29. // Use junit platform for unit tests
  30. useJUnitPlatform()
  31. }
  32. jar {
  33. // Line below does the trick if you are using 'gradlew jar'
  34. // Shout out / big ups to: Chriki
  35. // Note: My solution (using shadow gradle plugin)
  36. // does not require this, but it doesn't hurt
  37. exclude 'META-INF/*.DSA'
  38. manifest {
  39. attributes "Main-Class": "foo.App"
  40. }
  41. zip64 = true
  42. from {
  43. configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
  44. }
  45. }
  46. // This was the second part of what I used in my solution
  47. // When building, specify: 'gradlew shadowJar' - the jar you want has -all* in it.
  48. // Run with: java -jar build/libs/foo-all.jar
  49. shadowJar {
  50. zip64 = true // I had to specify this twice.. OK.. not gonna lose sleep.
  51. }
展开查看全部

相关问题