使用Gradle创建可运行的JAR

Han*_*nes 128 java jar gradle

到目前为止,我通过Eclipse"Export ..."功能创建了可运行的JAR文件,但现在我切换到IntelliJ IDEA和Gradle进行构建自动化.

这里的一些文章提出了"应用程序"插件,但这并不完全导致我期望的结果(只是一个JAR,没有启动脚本或类似的东西).

如何通过Eclipse"Export ..."对话框实现相同的结果?

JB *_*zet 147

可执行jar文件只是一个jar文件,其清单中包含Main-Class条目.所以你只需要配置jar任务就可以在它的清单中添加这个条目:

jar {
    manifest {
        attributes 'Main-Class': 'com.foo.bar.MainClass'
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这似乎是我在寻找的东西; 但是:我已经在build.gradle中声明了依赖项,我是否真的必须手动添加类路径,还是可以重新使用我的依赖声明? (5认同)
  • “ inseid“运行时”配置是什么意思?对不起愚蠢的问题,我是Gradle的新手... (3认同)

dav*_*c24 90

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

在最简单的形式中,使用Gradle创建可执行JAR只需要向清单添加适当的条目.但是,在类路径中包含需要包含的依赖项更为常见,这使得这种方法在实践中变得棘手.

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

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

第三种方法是创建一个所谓的"胖JAR",它是一个可执行的JAR,不仅包括组件的代码,还包括它的所有依赖项.有一些不同的插件使用这种方法.我已经包含了一些我所知道的链接; 我相信还有更多.


Mar*_*son 31

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

我已经尝试了各种插件组合,而不是创建可执行jar的简单任务,不知怎的,包括依赖项.所有插件似乎都缺乏这种或那种方式,但最后我得到了它就像我想要的那样.没有神秘的脚本,没有一百万个不同的迷你文件污染构建目录,一个非常干净的构建脚本文件,最重要的是:没有一百万个外国第三方类文件合并到我的jar存档中.

以下是从复制粘贴在这里为您提供方便..

[如何]在子目录中创建具有依赖项jars的分发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:
    //     https://stackoverflow.com/questions/22659463/add-classpath-in-manifest-using-gradle
    //     https://gist.github.com/simon04/6865179
}
Run Code Online (Sandbox Code Playgroud)

在这里担任要点.

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

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

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

清单 - 版本:1.0
Main-Class:com.somepackage.MainClass
Class-Path:lib/commons-lang3-3.3.2.jar


Ost*_*tan 23

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

除了应用插件之外,还需要做的是:

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

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

  • 运行gradle任务./gradlew shadowJar

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

最后通过以下方式执行:

jar {
  manifest {
   attributes 'Main-Class': 'com.my.app.Main'
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个[完整的`build.gradle`示例](https://gist.github.com/TurekBot/4a3cd406cb52dfd8bfb8022b982f0f6c)。 (2认同)

Mah*_*zad 16

这是针对Kotlin DSL (build.gradle.kts )。

方法1(不需要application或其他插件)

tasks.jar {
    manifest.attributes["Main-Class"] = "com.example.MyMainClass"
    // OR another notation
    // manifest {
    //     attributes["Main-Class"] = "com.example.MyMainClass"
    // }
}
Run Code Online (Sandbox Code Playgroud)

如果您使用任何外部库,请使用以下代码。将库 JAR 复制到放置结果 JAR 的libs子目录中。确保您的库 JAR 文件的文件名中不包含空格。

tasks.jar {
    manifest.attributes["Main-Class"] = "com.example.MyMainClass"
    manifest.attributes["Class-Path"] = configurations
        .runtimeClasspath
        .get()
        .joinToString(separator = " ") { file ->
            "libs/${file.name}"
        }
}
Run Code Online (Sandbox Code Playgroud)

请注意,Java 要求我们对属性使用相对 URL Class-Path。所以,我们不能使用Gradle依赖的绝对路径(这也容易被改变并且在其他系统上不可用)。如果您想使用绝对路径,也许这个解决方法会起作用。

使用以下命令创建 JAR:

./gradlew jar
Run Code Online (Sandbox Code Playgroud)

默认情况下,结果 JAR 将在build/libs/目录中创建。

方法 2:将库(如果有)嵌入到结果 JAR(fat 或 uber JAR)中

tasks.jar {
    manifest.attributes["Main-Class"] = "com.example.MyMainClass"
    val dependencies = configurations
        .runtimeClasspath
        .get()
        .map(::zipTree) // OR .map { zipTree(it) }
    from(dependencies)
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
Run Code Online (Sandbox Code Playgroud)

创建 JAR 与之前的方法完全相同。

方法 3:使用Shadow 插件(创建 fat 或 uber JAR)

plugins {
    id("com.github.johnrengelman.shadow") version "6.0.0"
}
// Shadow task depends on Jar task, so these will be reflected for Shadow as well
tasks.jar {
    manifest.attributes["Main-Class"] = "org.example.MainKt"
}
Run Code Online (Sandbox Code Playgroud)

使用以下命令创建 JAR:

./gradlew shadowJar
Run Code Online (Sandbox Code Playgroud)

有关配置插件的更多信息,请参阅Shadow 文档。

运行创建的 JAR

java -jar my-artifact.jar
Run Code Online (Sandbox Code Playgroud)

上述解决方案经过以下测试:

  • 爪哇17
  • Gradle 7.1(使用 Kotlin 1.4.31 进行.kts构建脚本)

有关创建 uber (fat) JAR 的信息,请参阅官方Gradle 文档。

有关清单的更多信息,请参阅Oracle Java 文档:使用清单文件

请注意,您的资源文件将自动包含在 JAR 文件中(假设它们放置在/src/main/resources/目录中或在构建文件中设置为资源根目录的任何自定义目录中)。要访问应用程序中的资源文件,请使用以下代码(请注意/名称开头的 ):

  • 科特林
    val vegetables = MyClass::class.java.getResource("/vegetables.txt").readText()
    // Alternative ways:
    // val vegetables = object{}.javaClass.getResource("/vegetables.txt").readText()
    // val vegetables = MyClass::class.java.getResourceAsStream("/vegetables.txt").reader().readText()
    // val vegetables = object{}.javaClass.getResourceAsStream("/vegetables.txt").reader().readText()
    
    Run Code Online (Sandbox Code Playgroud)
  • 爪哇
    var stream = MyClass.class.getResource("/vegetables.txt").openStream();
    // OR var stream = MyClass.class.getResourceAsStream("/vegetables.txt");
    var reader = new BufferedReader(new InputStreamReader(stream));
    var vegetables = reader.lines().collect(Collectors.joining("\n"));
    
    Run Code Online (Sandbox Code Playgroud)


Jor*_*e_B 5

你试过'installApp'任务吗?它是否不使用一组启动脚本创建完整目录?

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

  • 是的,在Gradle 3.0中,`installApp`被重命名为`installDist`。这是[发行说明](https://docs.gradle.org/3.0/release-notes.html)。 (2认同)

小智 5

谢谢康斯坦丁,它就像一个魅力,没有什么细微差别。由于某种原因,将主类指定为 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'
}
Run Code Online (Sandbox Code Playgroud)

运行 gradle ShadowJar 后,您会在构建文件夹中获得 myapp-{version}-all.jar,它可以作为 java -jar myapp-{version}-all.jar 运行。


Top*_*era 5

您可以使用 SpringBoot 插件:

plugins {
  id "org.springframework.boot" version "2.2.2.RELEASE"
}
Run Code Online (Sandbox Code Playgroud)

创建罐子

gradle assemble
Run Code Online (Sandbox Code Playgroud)

然后运行它

java -jar build/libs/*.jar
Run Code Online (Sandbox Code Playgroud)

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