用 Gradle 创建可运行的 JAR

到目前为止,我通过 Eclipse 的“ Export...”功能创建了可运行的 JAR 文件,但是现在我转到了 IntelliJ 的 IDEA 和 Gradle 组建自动化。

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

我怎样才能得到 Eclipse 在“ Export...”对话框中得到的相同结果呢?

269928 次浏览

你试过“ installApp”任务吗? 它没有创建一个包含一组启动脚本的完整目录吗?

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

可执行 jar 文件只是一个 jar 文件,其清单中包含 Main-Class 条目。因此,您只需要配置 罐子任务,以便在其清单中添加这个条目:

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

您可能还需要在清单中添加类路径条目,但是方法是相同的。

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

JB Nizet 和 Jorge _ B 的答案都是正确的。

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

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

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

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

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

  • 右键单击 module > Open module Settings > Artiacts > + > JAR > from module with Dependency。
  • 设置主类。

制作一个罐子就像从 Build 菜单中点击“ Build 神器...”一样简单。另外,您还可以将所有依赖项打包到一个 jar 中。

在 IntelliJ IDEA 14终极版上测试。

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

我已经尝试了各种各样的插件组合,为了创建一个可执行的 jar 这样一个简单的任务,并且以某种方式包含了依赖关系。所有的插件似乎都缺少这样或那样的方式,但最终我得到了我想要的。没有神秘的脚本,没有一百万个不同的迷你文件污染构建目录,一个相当干净的构建脚本文件,最重要的是: 没有一百万个外部第三方文件合并到我的 jar 归档中。

以下是从 给你复制粘贴,以方便您。

[ How-to ]在子目录 /lib中创建一个包含依赖项 jar 的分发压缩文件,并将所有依赖项添加到清单文件中的 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
}

主机作为一个要点 给你

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

Lib/commons-lang3.3.3.2. jar
Jar < br >

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

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

对我来说,最省力的解决方案就是利用 渐变-阴影-插件

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

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

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

运行分级任务

./gradlew shadowJar

Build/libs/中取出 < em > app-version-all.jar

最后通过以下方式执行:

java -jar app-version-all.jar

谢谢你,康斯坦丁,它的工作就像一个魅力,几乎没有细微差别。由于某些原因,将 main 类指定为 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 之后,您将在构建文件夹中获得 myapp-{ version }-all.jar,它可以作为 java-jar 运行。

我检查了相当多的解决方案的链接,最后做了下面提到的步骤让它工作。我用的是2.9级。

在你的构建、分级文件中做以下更改:

  1. 提到插件:

    apply plugin: 'eu.appsatori.fatjar'
    
  2. Provide the Buildscript:

    buildscript {
    repositories {
    jcenter()
    }
    
    
    dependencies {
    classpath "eu.appsatori:gradle-fatjar-plugin:0.3"
    }
    }
    
  3. Provide the Main Class:

    fatJar {
    classifier 'fat'
    manifest {
    attributes 'Main-Class': 'my.project.core.MyMainClass'
    }
    exclude 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.SF'
    }
    
  4. Create the fatjar:

    ./gradlew clean fatjar
    
  5. Run the fatjar from /build/libs/ :

    java -jar MyFatJar.jar
    

你可以使用 SpringBoot 插件:

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

创建罐子

gradle assemble

然后运行它

java -jar build/libs/*.jar

注意: 你的项目不需要是一个 SpringBoot 项目来使用这个插件。

  1. 将主类配置为清单

如果您正在使用 gradle project,只需将以下内容添加到 build.gradle 中

jar {
manifest {
attributes(
'Main-Class': 'pokerhandscorer.PokerHandScorer'
)
}
}
  • 其中“ pokerhandscorer”是包名称的名称, PokerHandScorer 是主类名

这将在构建库{ jarFilename } . jar 中创建一个 jar 文件

  1. 使用 java-jar/{ path }/{ jarFileName.jar }运行 jar 文件

Java-jar/{ path }/{ jarFileName.jar }

以下是我在“等级6.7”中尝试过的解决方案

可运行的胖罐子(将所有依赖库复制到 Jar 中)

task fatJar(type: Jar) {
   

manifest {
attributes 'Main-Class': 'com.example.gradle.App'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
} with jar
    

}

可运行的 jar,将所有依赖项复制到一个目录并将类路径添加到清单中

    def dependsDir = "${buildDir}/libs/dependencies/"
task copyDependencies(type: Copy) {
from configurations.compile
into "${dependsDir}"
}
task createJar(dependsOn: copyDependencies, type: Jar) {
      

manifest {
attributes('Main-Class': 'com.example.gradle.App',
'Class-Path': configurations.compile.collect { 'dependencies/' + it.getName() }.join(' ')
)
}
with jar
}

怎么用?

  • 将上述任务添加到 build.gradle
  • 执行 gradle fatJar//create fatJar
  • 执行带有复制依赖项的 gradle createJar//create jar。

更多细节: https://jafarmlp.medium.com/a-simple-java-project-with-gradle-2c323ae0e43d

这是用于 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"
// }
}

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

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

注意,Java 要求我们对 Class-Path属性使用相对 URL。因此,我们不能使用 Gradle 依赖关系的绝对路径(它也很容易被更改,而且在其他系统上不可用)。如果您想使用绝对路径,也许 这个变通方案可以工作。

使用以下命令创建 JAR:

./gradlew jar

默认情况下,结果 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
}

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

方法3: 使用 阴影插件(创建一个胖的或超级的 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"
}

使用以下命令创建 JAR:

./gradlew shadowJar

有关配置插件的更多信息,请参见 影子文件

运行创建的 JAR

java -jar my-artifact.jar

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

  • 爪哇17
  • Gradle 7.1(对于 。 kts构建脚本使用 Kotlin 1.4.31)

见官方 用于创建 uber (fat) JAR 的 Gradle 文档

有关清单的详细信息,请参阅 Oracle Java 文档: 使用 Manifest 文件

请注意,您的资源文件将自动包含在 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()
    
  • 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"));