如何在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) }
快速回答
-
将以下内容添加到您的
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议添加应用程序版本到您的build.gradle
,但它不是必需的。 如果你这样做,build立的jar名称将是<appname>-<version>.jar
。
注意:我正在使用gradle 2.5
细节
为了创build一个自包含的可执行jar,你可以简单地运行:
java -jar appname.jar
你会需要:
- 你的jar包括指向你的应用程序主类的清单文件
- 你的所有依赖项(来自应用程序之外的jar的类)被包含或以某种方式访问
- 您的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