使用Gradle创建可运行的JAR


147

到目前为止,我已经通过Eclipse的“导出...”功能创建了可运行的JAR文件,但是现在我切换到IntelliJ IDEA和Gradle进行构建自动化。

这里有一些文章建议使用“应用程序”插件,但这并不能完全导致我期望的结果(只是JAR,没有启动脚本或类似的东西)。

如何通过Eclipse的“导出...”对话框获得相同的结果?

Answers:


164

可执行jar文件只是清单中包含Main-Class条目的jar文件。因此,您只需要配置jar任务即可在清单中添加此条目:

jar {
    manifest {
        attributes 'Main-Class': 'com.foo.bar.MainClass'
    }
}

您可能还需要在清单中添加类路径条目,但这将以相同的方式完成。

参见http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html


5
这似乎是我想要的。但是:我已经在build.gradle中声明了依赖关系,我真的必须手动添加类路径吗?还是可以重用依赖关系声明?
汉尼斯

您应该能够遍历“运行时”配置中的库,并将它们连接起来以创建Class-Path属性值。
JB Nizet 2014年

3
“ inseid“运行时”配置”是什么意思?对不起愚蠢的问题,我对Gradle还是很陌生……
Hannes 2014年

gradle java插件定义了对应于4个不同类路径的4个“配置”:编译(用于编译Java文件),testCompile(用于编译测试Java源文件),运行时(用于执行应用程序)和testRuntime(用于执行测试)。参见gradle.org/docs/current/userguide/…–
JB Nizet

啊,谢谢-我理解它正确无误,并设法构建了JAR,现在我正在创建类路径;-)非常感谢您的帮助!
汉尼斯,2014年

97

JB Nizet和Jorge_B的答案都是正确的。

以最简单的形式,使用Gradle创建可执行JAR只是将适当的条目添加到manifest即可。但是,在类路径中包含依赖项的情况更为常见,因此这种方法在实践中很棘手。

应用的插件提供了一种替代方法; 它提供了以下功能,而不是创建可执行的JAR:

  • 一项run任务,可以轻松地直接从构建中轻松运行应用程序
  • 一个installDist任务,该任务生成一个目录结构,其中包括内置的JAR,它依赖的所有JAR以及一个将其全部组合到可以运行的程序中的启动脚本
  • distZipdistTar创建包含完整应用程序分发的归档的任务(启动脚本和JAR)

第三种方法是创建一个所谓的“胖JAR”,它是一个可执行JAR,它不仅包括组件的代码,还包括其所有依赖项。有几种使用这种方法的插件。我提供了一些我知道的链接。我敢肯定还有更多。


刚刚尝试了阴影和一个罐子。我会坚持一罐子:它更简单易用。凉!谢谢
Jako

不幸的是,一罐子不适用于最新版本的Gradle。参见例如github.com/rholder/gradle-one-jar/issues/34
pharsicle

是通过修改jar任务来构建一个jar的单线解决方案。我发现这是最方便的。请注意,您需要configurations.runtime在单个jar中添加捆绑运行时依赖项。
Quazi Irfan

我发现“应用程序插件”足够适合我的需求,并且足够灵活。它还允许将所有内容打包为zip,并在该zip中包含/排除其他文件。此外,还可以使用自定义任务添加另一个带有附加入口点的启动器脚本。
kinORnirvana

我将如何执行生成的.tar/ .zip文件?
Tobiq

35

正如其他人指出的那样,为了使jar文件可执行,必须Main-Class在清单文件的属性中设置应用程序的入口点。如果依赖项类文件未并置,则需要Class-Path在清单文件的条目中进行设置。

我已经尝试了各种插件组合,而对于创建可执行jar的简单任务却没有尝试,并且某种程度上包括了依赖项。所有插件似乎都缺少一种或另一种方式,但最终我得到了想要的结果。没有神秘的脚本,没有一百万个不同的迷你文件污染了构建目录,一个非常干净的构建脚本文件,最重要的是:没有一百万个外国第三方类文件合并到我的jar档案中。

为了方便起见,以下是从此处复制粘贴的信息。

[操作方法]在子目录中创建具有依赖项jar的分发zip文件,/lib并将所有依赖Class-Path项添加到清单文件中的条目中:

apply plugin: 'java'
apply plugin: 'java-library-distribution'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.apache.commons:commons-lang3:3.3.2'
}

// Task "distZip" added by plugin "java-library-distribution":
distZip.shouldRunAfter(build)

jar {
    // Keep jar clean:
    exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'

    manifest {
        attributes 'Main-Class': 'com.somepackage.MainClass',
                   'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' ')
    }
    // How-to add class path:
    //     /programming/22659463/add-classpath-in-manifest-using-gradle
    //     https://gist.github.com/simon04/6865179
}

在这里担任要点。

可以在中找到结果build/distributions,解压缩后的内容如下所示:

lib / commons-lang3-3.3.2.jar
MyJarFile.jar

内容MyJarFile.jar#META-INF/MANIFEST.mf

清单版本:1.0
主类:com.somepackage.MainClass
类路径:lib / commons-lang3-3.3.2.jar


当前的应用程序jar也将在发行版的'lib'目录中。您必须将其移动到顶层目录或更改以下行:'Class-Path':configuration.runtime.files.collect {“ lib / $ it.name”} .join('')}到此: 'Class-Path':configuration.runtime.files.collect {“ $ it.name”} .join('')}
Marc Nuri

1
@MarcNuri确定吗?我尝试对我的应用程序使用此方法,并且此答案表明,当前的应用程序jar 不在lib生成的zip / tar文件的目录中,而是在lib的父目录中。该解决方案似乎对我来说是完美的。
thejonwithnoh 2015年

1
@thejonwithnoh对不起,您是对的。我没有看到建议使用“ java-library-distribution”插件的解决方案。就我而言,我只是在使用“应用程序”插件,该插件的功能相同,主要区别在于所有jar文件(包括应用程序jar)都位于“ lib”目录中。因此更改"lib/$it.name"为即可"$it.name"完成工作。
马克·努里

27

对我来说,最省力的解决方案是使用gradle-shadow-plugin

除了应用插件外,所有需要做的是:

配置jar任务以将Main类放入清单

jar {
  manifest {
   attributes 'Main-Class': 'com.my.app.Main'
  }
}

运行gradle任务

./gradlew shadowJar

build / libs /中获取app-version-all.jar

最后通过以下命令执行它:

java -jar app-version-all.jar


当我执行此构建时,我获得了BUILD SUCCESSFUL,但当我尝试使用java -jar build / libs / core-all-1.0.jar运行jar文件时,出现以下错误:错误:无法找到或加载主类scans.exchange。主要由:java.lang.ClassNotFoundException:scanners.exchange.Main您知道我该如何解决?
Luka Lopusina

@LukaLopusina您指定的类不在您的JAR文件中。如果您使用的是Kotlin,则需要说'com.my.app.MainKt'。没有更多信息,我无法进一步帮助您。
byxor

当前插件Shadow v5。+仅与Gradle 5.0+和Java 7+兼容。
Zon

5

您是否尝试过“ installApp”任务?是否不使用一组启动脚本创建完整目录?

http://www.gradle.org/docs/current/userguide/application_plugin.html


据我了解,installApp不会创建META-INF/MANIFEST.MF文件。难道我做错了什么?
2014年

1
installApp在“ 应用程序插件”的任务列表中看不到任务。您是说意思installDist吗?
Quazi Irfan '18

2
是的,installAppinstallDist在Gradle 3.0中重命名为。这是发行说明
Quazi Irfan,

4

谢谢康斯坦丁(Konstantin),它像一种魅力,几乎没有任何细微差别。出于某种原因,将主类指定为jar清单的一部分并不能很好地工作,而是需要mainClassName属性。这是build.gradle的一个片段,其中包括使之正常工作的所有内容:

plugins {
  id 'java' 
  id 'com.github.johnrengelman.shadow' version '1.2.2'
}
...
...
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
...
...
mainClassName = 'com.acme.myapp.MyClassMain'
...
...
...
shadowJar {
    baseName = 'myapp'
}

运行gradle shadowJar之后,您将在build文件夹中获取myapp- {version} -all.jar,可以将其作为java -jar myapp- {version} -all.jar运行。


3

您可以在模块设置(或项目结构)中定义jar工件。

  • 在具有依赖性的模块中,右键单击模块>打开模块设置>工件> +> JAR>。
  • 设置主类。

这样,制作罐子​​就像从“构建”菜单中单击“构建工件...”一样简单。另外,您可以将所有依赖项打包到一个jar中。

在IntelliJ IDEA 14 Ultimate上测试。


2

我检查了很多解决方案的链接,最后做了以下提到的步骤使它起作用。我正在使用Gradle 2.9。

在您的build,gradle文件中进行以下更改:

  1. 提及插件:

    apply plugin: 'eu.appsatori.fatjar'
  2. 提供构建脚本:

    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. 创建胖子:

    ./gradlew clean fatjar
  5. 从/ build / libs /运行fatjar:

    java -jar MyFatJar.jar

1
从2019年开始:此建议在这里不起作用。Fatjar文件中不包含任何依赖项
卡尔,

1

您可以使用SpringBoot插件:

plugins {
  id "org.springframework.boot" version "2.2.2.RELEASE"
}

创建罐子

gradle assemble

然后运行

java -jar build/libs/*.jar

注意:您的项目不需要是SpringBoot项目即可使用此插件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.