如何在Gradle中导出一个可执行的jar,这个jar可以运行,因为它包含了引用库

如何在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生成文件夹,并在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 

我怎样才能运行它的参考库?

您可以使用Gradle应用程序插件来实现它

希望这有助于某人(因为我不幸花了相当一段时间试图find解决scheme)。 这是为我创build可执行JAR的解决scheme。 我在主要方法中embeddeddocker,docker9是具体的,并使用Gradle 2.1。

将下面的代码包含到你的build.gradle文件中(如果一个子项目是需要构buildjar的“main”项目,那么将它添加到应该像这个项目一样启动的子项目中(':'){插入代码在这里,依赖关系之后。}

此外,你需要添加插件Java来这个工作:申请插件:'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。

这个问题似乎与embedded式Jetty有关,因为Jetty移动到了Eclipse中,现在正在签名他们的JAR,当其他未签名的JAR想要加载已签名的JAR时,我就读了这个JAR。 请随时教育我,如果我错了,这就是我读的。

项目所依赖的JAR在依赖关系中定义如下:

 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之后(在手动清理build目录之后)运行jar的时候,会抛出一个NoClassDefFoundException(在我们的项目中有许多子项目),但是在执行gradle clean build(第二次)之后运行jar清空生成目录手动),出于某种原因,它有所有的依赖。 如果省略asFileTree.files,则不会发生这种情况。

另外我应该注意的是,所有的编译依赖都包含在运行时,但并不是所有的运行时都包含在编译中。 所以,如果你只是使用编译

  configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } 

那么一定要记住,如果抛出了NoClassDefFoundException,那么在运行时没有find某个类,这意味着你也应该包含这个:

  configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } 

快速回答

  1. 将以下内容添加到您的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(' ') } } 
  2. 从项目目录运行gradle installDist
  3. 运行java -jar build/install/<appname>/lib/<appname>.jar

我build议添加应用程序版本到您的build.gradle ,但它不是必需的。 如果你这样做,build立的jar名称将是<appname>-<version>.jar

注意:我正在使用gradle 2.5


细节

为了创build一个自包含的可执行jar,你可以简单地运行:

 java -jar appname.jar 

你会需要:

  1. 你的jar包括指向你的应用程序主类的清单文件
  2. 你的所有依赖项(来自应用程序之外的jar的类)被包含或以某种方式访问
  3. 您的MANIFEST文件包含正确的类path

正如其他一些答案指出的,你可以使用一些第三方插件来实现这一点,如阴影或单jar 。

我试过阴影,但不喜欢这样一个事实,即我的所有依赖和资源都与我的应用程序代码一起放入构build的jar中。 我也倾向于尽量减less使用外部插件。

另一个select是使用gradle应用程序插件,如上面的@erdi所回答的。 运行gradle build将为您构build一个jar包,并将其与您的所有依赖关系很好地捆绑在一个zip / tar文件中。 你也可以运行gradle installDist来跳过压缩。

然而 ,正如@jeremyjjbrown在那里写了一个评论,插件本身并没有创build一个可执行的jar。 它创build一个jar和一个脚本来构build类path,并执行一个命令来运行你的应用程序的主类。 您将无法运行java -jar appname.jar

要获得两全其美的效果,请按照上述步骤将所有依赖关系创build为独立的jar,并将正确的值添加到MANIEST。

我检查了解决scheme的一些链接,最后做了下面提到的步骤来得到它的工作。 我正在使用Gradle 2.9。

在您的构buildGradle文件中进行以下更改:

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.创buildfatjar:

 ./gradlew clean fatjar 

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

 java -jar MyFatJar.jar 

所有这些答案都是错误的或过时的。

OP是要求什么被称为“胖jar子”。 这是一个可执行的jar包含所有的依赖关系,所以它不需要外部依赖为了运行(除了JRE当然!)。

在编写本文的时候,答案就是Gradle Shadow Jar插件,在Shadow Plugin用户指南和示例中已经很清楚地解释了这个问题。

因为我是一个无知的人,所以我仍然挣扎了一下。 更具体地说,我已经使用了几个月的Gradle作为这个“魔术盒”。 有一半时间我不太清楚它做得怎么样,或者它是如何做的(目前对Groovy语言没有太大的兴趣)。 只要知道它可以做testing和运行我想要的东西。

所以这样做:

把所有这些行放在你的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不要担心任何其他“存储库”,“依赖”或“插件”行在您的构build文件中的其他地方,并这个“buildscript”块内的行(我不知道你为什么需要做那)。

PPS的阴影插件用户指南及例子是写得很好,但不会告诉你包括该行

 attributes 'Main-Class': 'core.MyClassContainingMainMethod' 

我已经把它放在上面了。 也许是因为作者认为你比我不那么笨,而且你可能是。 我不知道为什么我们被告知要放入一个奇怪的“类path”属性,但是如果没有破坏,就不要修复它。

当你然后去

 > gradle shadowjar 

Gradle将希望在/ build / libs(默认名称为“shadow.jar”)下创build一个胖的可执行文件,你可以这样做:

 > java -jar shadow.jar