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

jyc*_*han 41 executable jar reference noclassdeffounderror gradle

如何在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.+'
    )
}
Run Code Online (Sandbox Code Playgroud)

在我运行之后: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
Run Code Online (Sandbox Code Playgroud)

我如何使用参考库运行它?

erd*_*rdi 17

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

  • Gradle应用程序插件不会创建可执行jar. (10认同)
  • 我不想得到一个zip或tar文件,只需要一个文件夹中的依赖库JAR (8认同)

fla*_*ngo 17

希望这有助于某人(因为我不幸地花了很长时间试图找到解决方案).这是为我创建可执行JAR的解决方案.我在主要方法中嵌入Jetty,Jetty 9是特定的并使用Gradle 2.1.

在build.gradle文件中包含以下代码(如果子项目是需要构建jar的"主"项目,则将其添加到子项目中,该子项目应该像这个项目一样开始(':'){插入代码在某处,在依赖之后.}.

此外,您需要添加插件java才能正常工作:apply plugin:'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'
}
Run Code Online (Sandbox Code Playgroud)

然后你可以通过命令行执行你的yourjar.jar:

java -jar yourjar.jar
Run Code Online (Sandbox Code Playgroud)

必须排除META-INF/.RSA,META-INF / .SF和META-INF/*.DSA才能使其工作.否则抛出SecurityException.

问题似乎在于嵌入式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'

}
Run Code Online (Sandbox Code Playgroud)

编辑:之前,而不仅仅是

configurations.runtime.collect{...}
Run Code Online (Sandbox Code Playgroud)

我有

configurations.runtime.asFileTree.files.collect{...}
Run Code Online (Sandbox Code Playgroud)

这在干净的构建中的大型项目中引起了奇怪的行为.在第一次执行gradle clean build之后运行jar时(在手动清理构建目录之后),它会抛出NoClassDefFoundException(在我们的项目中有很多子项目),但是在第二次执行gradle clean build之后运行jar(没有手动清空构建目录),由于某种原因它具有所有依赖项.如果省略asFileTree.files,则不会发生这种情况.

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

        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
Run Code Online (Sandbox Code Playgroud)

然后一定要记住,如果抛出NoClassDefFoundException,则在运行时找不到某个类,这意味着您还应该包括:

        configurations.runtime.collect {
            it.isDirectory() ? it : zipTree(it)
        }
Run Code Online (Sandbox Code Playgroud)


ela*_*anh 10

快速回答

  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(' ')
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 从项目目录中运行 gradle installDist
  3. java -jar build/install/<appname>/lib/<appname>.jar

我建议您同时添加应用版本build.gradle,但这不是必需的.如果这样做,建立的jar名称将是<appname>-<version>.jar.

注意:我正在使用gradle 2.5


细节

为了创建一个自包含的可执行jar,你只需运行:

java -jar appname.jar
Run Code Online (Sandbox Code Playgroud)

你会需要:

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

正如其他一些答案所指出的,你可以使用一些第三方插件来实现这一点,例如shadowone-jar.

我尝试了阴影,但不喜欢这样一个事实:我的所有依赖项和它们的资源都与我的应用程序代码一起被抛弃到构建的jar中.我也更喜欢尽量减少使用外部插件.

另一个选择是使用gradle应用程序插件,如上面回答的@erdi.Running gradle build会为你构建一个jar,并很好地将它与zip/tar文件中的所有依赖项捆绑在一起.你也可以跑去gradle installDist跳过拉链.

但是,正如@jeremyjjbrown在评论中所写,插件本身并不会创建可执行jar.它创建了一个jar和一个脚本,用于构造类路径并执行命令来运行应用程序的主类.你将无法运行java -jar appname.jar.

要充分利用这两个方面,请按照上面的步骤创建您的jar以及所有依赖项作为单独的jar,并将正确的值添加到MANIEST.


mik*_*ent 5

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

OP正在询问所谓的“胖罐”。那是一个可执行的jar,其中包含所有依赖项,因此它不需要外部依赖项即可运行(当然,除了JRE!)。

撰写本文时的答案是Gradle Shadow Jar插件,在Shadow Plugin User Guide&Examples中非常清楚地说明了这一点。

我有点挣扎。但这有效:

将所有这些行放在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'
    }
}
Run Code Online (Sandbox Code Playgroud)

PS不必担心构建文件中其他位置的任何其他“存储库”,“依赖项”或“插件”行,因此不必将这些行留在此“ buildscript”块中(我不知道为什么需要这样做那)。

PPS Shadow Plugin用户指南和示例写得很好,但没有告诉您包括该行

attributes 'Main-Class': 'core.MyClassContainingMainMethod'
Run Code Online (Sandbox Code Playgroud)

我放在上面的地方。也许是因为作者认为您不像我那么笨,而您也可能如此。我不知道为什么要告诉我们放置一个像这样的奇怪的“ Class-Path”属性,但是如果它没有损坏,就不要修复它。

你什么时候走

> gradle shadowjar
Run Code Online (Sandbox Code Playgroud)

Gradle有望在/ build / libs(默认名称为“ shadow.jar”)下构建一个胖的可执行jar,您可以通过执行以下操作来运行它:

> java -jar shadow.jar
Run Code Online (Sandbox Code Playgroud)