如何在 gradle 中导出可执行 jar,并且这个 jar 可以运行,因为它包含参考库
Posted
技术标签:
【中文标题】如何在 gradle 中导出可执行 jar,并且这个 jar 可以运行,因为它包含参考库【英文标题】:how to export a executable jar in gradle, and this jar can run as it include reference libraries 【发布时间】:2013-01-16 08:47:21 【问题描述】:如何在 gradle 中导出一个可执行的 jar,这个 jar 可以运行,因为它包含了参考库。
build.gradle
apply plugin: 'java'
manifest.mainAttributes("Main-Class" : "com.botwave.analysis.LogAnalyzer")
repositories
mavenCentral()
dependencies
compile (
'commons-codec:commons-codec:1.6',
'commons-logging:commons-logging:1.1.1',
'org.apache.httpcomponents:httpclient:4.2.1',
'org.apache.httpcomponents:httpclient:4.2.1',
'org.apache.httpcomponents:httpcore:4.2.1',
'org.apache.httpcomponents:httpmime:4.2.1',
'ch.qos.logback:logback-classic:1.0.6',
'ch.qos.logback:logback-core:1.0.6',
'org.slf4j:slf4j-api:1.6.0',
'junit:junit:4.+'
)
运行后:gradle build
它创建构建文件夹,我在 build/libs/XXX.jar 中运行 jar:
java -jar build/libs/XXX.jar
这里有一个执行说:
Exception in thread "main" java.lang.NoClassDefFoundError: ch/qos/logback/core/joran/spi/JoranException
如何使用参考库运行它?
【问题讨论】:
【参考方案1】:你可以通过Gradle application plugin实现它
【讨论】:
酷,我不知道他们添加了这个。我一直使用“fat jar”配方,并为主类手动添加了一个清单条目。 他们在 1.0 版本左右添加了这一点 我不想获取 zip 或 tar 文件,只需要文件夹中的依赖库 JAR Gradle 应用程序插件不创建可执行 jar。 使用 Gradle 应用插件无法实现。【参考方案2】:希望这对某人有所帮助(不幸的是,我花了很长时间试图找到解决方案)。这是对我有用的创建可执行 JAR 的解决方案。我将 Jetty 嵌入到主要方法中,具体来说是 Jetty 9 并使用 Gradle 2.1。
在您的 build.gradle 文件中包含以下代码(如果子项目是需要构建 jar 的“主”项目,则将其添加到应该像此项目一样开始的子项目中(':')在依赖项之后的某处插入代码。。
此外,您需要添加插件 java 才能工作:apply plugin: 'java' 。
我的 jar 任务如下所示:
apply plugin: 'java'
jar
archiveName = "yourjar.jar"
from
configurations.runtime.collect
it.isDirectory() ? it : zipTree(it)
configurations.compile.collect
it.isDirectory() ? it : zipTree(it)
manifest
attributes 'Main-Class': 'your.package.name.Mainclassname'
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
然后你可以通过命令行执行你的 yourjar.jar:
java -jar yourjar.jar
必须排除 META-INF/.RSA、META-INF/.SF 和 META-INF/*.DSA 才能正常工作。否则会抛出 SecurityException。
问题似乎出在嵌入式 Jetty 上,因为 Jetty 迁移到 Eclipse,现在正在签署他们的 JAR,当其他未签名的 JAR 想要加载已签名的 JAR 时,我读到这会成为问题。如果我在这方面错了,请随时教育我,这就是我读到的。
项目所依赖的JAR在dependencies中定义如下:
dependencies
// add the subprojects / modules that this depends on
compile project(':subproject-1')
compile project(':subproject-2')
compile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.2.6.v20141205'
compile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.2.6.v20141205'
compile group: 'org.eclipse.jetty', name: 'jetty-http', version: '9.2.6.v20141205'
编辑:之前,而不仅仅是
configurations.runtime.collect...
我有
configurations.runtime.asFileTree.files.collect...
这在干净构建的大型项目中引起了奇怪的行为。第一次执行 gradle clean build 后运行 jar (手动清理构建目录后),会抛出 NoClassDefFoundException (在我们有很多子项目的项目中),但在第二次执行 gradle clean build 后运行 jar(没有手动清空构建目录),由于某种原因它具有所有依赖项。如果 asFileTree.files 被忽略,这不会发生。
另外我应该注意,所有编译依赖项都包含在运行时中,但并非所有运行时都包含在编译中。所以如果你只是使用编译
configurations.compile.collect
it.isDirectory() ? it : zipTree(it)
那么一定要记住,如果抛出了 NoClassDefFoundException,则在运行时找不到某些类,这意味着您还应该包含以下内容:
configurations.runtime.collect
it.isDirectory() ? it : zipTree(it)
【讨论】:
我还应该注意,在我的代码中,依赖项 ... 部分位于 jar ... 部分之前,以防相关。 -1 OP 是明确的:他/她想要创建一个包含所有“参考库”的“胖罐”。当然,你不是唯一一个回答错误问题的人。看我的回答。 我看不到 OP 在哪里使用“胖罐子”这个词。 OP 清楚地谈到了一个可执行的 jar。我知道可执行 jar 基本上被称为 fat jar,但这是否立即意味着您必须使用 fat jar 插件?我还明确说明了我正在使用哪些版本,所以是的,这可能已经过时了,但它适用于我提到的 gradle 等版本。 OP 不知道“胖罐子”这个词,我同意!但是如何解释这个想法:“这个 jar 可以运行,因为它包含参考库。”?当然,“参考库”这个术语是指构成依赖项的 jars ......并且 OP 想知道她/他为什么收到错误消息......“fat jar”表示可执行的 jar,是的,但具体 一个包含所有依赖项的 jars...【参考方案3】:快速解答
将以下内容添加到您的build.gradle
:
apply plugin: 'application'
mainClassName = 'org.example.app.MainClass'
jar
manifest
attributes 'Main-Class': mainClassName,
'Class-Path': configurations.runtime.files.collect "$it.name".join(' ')
从项目目录,运行gradle installDist
运行java -jar build/install/<appname>/lib/<appname>.jar
我建议您也将应用版本添加到您的build.gradle
,但这不是必需的。如果这样做,则构建的 jar 名称将为 <appname>-<version>.jar
。
注意:我使用的是 gradle 2.5
详情
为了创建一个可以简单运行的自包含可执行 jar:
java -jar appname.jar
你需要:
-
您的 jar 文件包含指向您的应用程序主类的 MANIFEST 文件
您的所有依赖项(来自应用程序外部 jar 的类)都将被包含或以某种方式访问
您的 MANIFEST 文件以包含正确的类路径
正如其他一些答案所指出的,您可以使用一些第三方插件来实现这一点,例如shadow 或one-jar。
我尝试了 shadow,但不喜欢 所有 我的依赖项及其资源与我的应用程序代码一起被完全倾倒到构建的 jar 中的事实。我也更喜欢尽量减少使用外部插件。
另一种选择是使用@erdi 上面回答的gradle application plugin。运行 gradle build
将为您构建一个 jar,并将它与您的所有依赖项很好地捆绑在一个 zip/tar 文件中。你也可以直接运行gradle installDist
跳过压缩。
然而,正如@jeremyjjbrown 在评论中所写的那样,插件不本身创建一个可执行的 jar。它创建一个 jar 和一个构建类路径并执行命令以运行应用程序的主类的脚本。你将无法运行java -jar appname.jar
。
为了两全其美,请按照上述步骤将您的 jar 与所有依赖项一起创建为单独的 jar,并将正确的值添加到您的 MANIEST。
【讨论】:
谢谢,如果我想创建一个包含所有依赖项的 jar,那可以工作,但是关于依赖项? @max 抱歉,我没有完全理解您的问题。以上将为您的应用程序创建一个 jar,其中包含所有依赖项作为单独的 jar。 MANIFEST 类路径将指向您所依赖的所有 jar。 是的,这是正确的,但如果我希望我的所有依赖项和应用程序都放在一个 jar 中怎么办? @max 我认为您可以使用我在答案中链接到的 shadow 或 one-jar 插件。【参考方案4】:所有这些答案要么是错误的,要么是过时的。
OP 要求的是所谓的“胖罐”。这是一个包含所有依赖项的可执行 jar,因此它不需要外部依赖项即可运行(当然 JRE 除外!)。
撰写本文时的答案是 Gradle Shadow Jar 插件,在 Shadow Plugin User Guide & Examples 上解释得很清楚。
我有点挣扎。但这有效:
将所有这些行放在 build.gradle 文件中的某个位置(我将它们放在顶部附近):
buildscript
repositories
jcenter()
dependencies
classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.4'
apply plugin: 'com.github.johnrengelman.shadow'
shadowJar
baseName = 'shadow'
classifier = null
version = null
jar
manifest
attributes 'Class-Path': '/libs/a.jar'
attributes 'Main-Class': 'core.MyClassContainingMainMethod'
PS 不要担心构建文件中其他地方的任何其他“存储库”、“依赖项”或“插件”行,并且做将这些行留在这个“buildscript”块中(我不知道为什么需要这样做)。
PPS Shadow Plugin User Guide & Examples 写得很好,但没有告诉你 包括该行
attributes 'Main-Class': 'core.MyClassContainingMainMethod'
我把它放在上面的地方。也许是因为作者认为你没有我那么无知,而你可能是。我不知道为什么我们被告知要在其中放置一个奇怪的“类路径”属性,但如果它没有损坏,请不要修复它。
你去的时候
> gradle shadowjar
Gradle 有望在 /build/libs(默认名称“shadow.jar”)下构建一个胖可执行 jar,您可以通过以下方式运行它:
> java -jar shadow.jar
【讨论】:
@elanh 答案使用 gradle 开箱即用,不需要 shadowjar @marcoslhc 我认为您没有理解这个问题:OP 想要一个包含其所有compile
依赖项 jar 的 jar。所以你可以把这个罐子放在任何地方,然后去java -jar myFatJar.jar
...它就会运行。 elanh 在对他的问题的评论中说了同样的话。
拯救我的一天!该解决方案适用于我 2018 年 2 月的项目。【参考方案5】:
我检查了很多解决方案的链接,最后完成了下面提到的步骤以使其正常工作。我正在使用 Gradle 2.9。
在您的 build、gradle 文件中进行以下更改:
1.提及插件:
apply plugin: 'eu.appsatori.fatjar'
2.提供 Buildscript:
buildscript
repositories
jcenter()
dependencies
classpath "eu.appsatori:gradle-fatjar-plugin:0.3"
3.提供主类:
fatJar
classifier 'fat'
manifest
attributes 'Main-Class': 'my.project.core.MyMainClass'
exclude 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.SF'
4.创建 fatjar:
./gradlew clean fatjar
5.从 /build/libs/ 运行 fatjar:
java -jar MyFatJar.jar
【讨论】:
试过这个...找不到'eu.appsatori.fatjar'。这里的plugins.gradle.org/plugin/eu.appsatori.fatjar 指向这里的github.com/musketyr/gradle-fatjar-plugin,上面写着“不再积极开发,改用“Gradle Shadow Plugin”。但至少你回答了这个问题!以上是关于如何在 gradle 中导出可执行 jar,并且这个 jar 可以运行,因为它包含参考库的主要内容,如果未能解决你的问题,请参考以下文章
我可以选择我在 Maven 依赖项中使用的唯一包来在 Eclipse 中导出可运行的 jar 吗?
从 Gradle 创建可执行 jar 文件并在 maven 中导入 jar
如何使用 Gradle 创建具有实现依赖项的可执行胖 jar
如何在 Eclipse IDE 中导出 Spring Boot Gradle 项目?