我正在尝试创建一个可执行的.jar,其中包含一些提供的依赖项,我有一个从'gradle init'创建的简单示例,在添加几个提供的依赖项之前,我可以执行.jar,但是添加这些依赖项之后它就失败了。
我可以复制如下:
mkdir /tmp/foo
cd /tmp/foo
run 'gradle init'
Select type of project to generate:
2: application
Select implementation language:
3: Java
Select build script DSL:
1: Groovy
Select test framework:
1: JUnit 4
Project name (default: foo):
Source package (default: foo):
然后在build.gradle的末尾添加以下内容:
jar {
manifest {
attributes "Main-Class": "foo.App"
}
zip64 = true
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
在命令行中,运行:
gradle clean ; gradle jar ; java -jar build/libs/foo.jar
你应该看到:
Hello world.
现在将build.gradle中的“dependencies”块更改为:
configurations {
provided
compile.extendsFrom(provided)
}
dependencies {
implementation 'com.google.guava:guava:29.0-jre'
testImplementation 'junit:junit:4.13'
implementation "org.apache.spark:spark-sql_2.11:2.4.4"
implementation "org.apache.spark:spark-hive_2.11:2.4.4"
}
在命令行中,再次运行:
gradle clean ; gradle jar ; java -jar build/libs/foo.jar
你应该看到一切都是好的:
Hello world.
下一步,请更换
implementation "org.apache.spark:spark-sql_2.11:2.4.4"
implementation "org.apache.spark:spark-hive_2.11:2.4.4"
具有
provided "org.apache.spark:spark-sql_2.11:2.4.4"
provided "org.apache.spark:spark-hive_2.11:2.4.4"
在命令行中,再次运行:
gradle clean ; gradle jar ; java -jar build/libs/foo.jar
这次您将获得:
Error: Could not find or load main class foo.App
因此,这显然是由于试图使spark相关的依赖项“被提供”,因此不是.jar的一部分。但是,您会注意到foo.app类非常简单,与spark无关。所以,我现在很困惑,为什么在添加这些类型的依赖项时主类突然变得不可用。提前感谢您的帮助!
2条答案
按热度按时间iovurdzv1#
您可能自己也注意到了(这可能也是您想要的):构建的jar文件包含您使用时所有依赖jar的全部内容
provided
(或compile
)而不是implementation
在dependencies
阻止。问题是你的
jar
任务配置实际上包含了依赖jar的所有内容,包括它们的META-INF/
目录文件。这些依赖jar中的一些似乎是经过签名的,因此在其内部包含数字签名META-INF/
目录–由您的jar
任务也是。运行时java -jar …
,这些签名会妨碍并导致类未找到错误(即使类在jar中)。一个简单的解决方法是在创建jar文件时排除签名:
学分归这个所以回答。
tktrz96b2#
下面是一个结合了chriki的解决方案和shadowjar方法的答案,shadowjar方法也对我有效。你挑吧!如果这篇文章对你有帮助,请投票给克里基。