如何在Gradle中复制依赖项库JAR文件

48

我有一个可运行的JAR文件,使用这个build.gradle文件构建。

    apply plugin: 'java'
    apply plugin: 'application'

    manifest.mainAttributes("Main-Class" : "com.test.HelloWorld")

    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.+'
        )
    }

但是运行失败了,因为找不到依赖的JAR包。

然后我添加了这段代码:

    task copyToLib(type: Copy) {
        into "$buildDir/output/libs"
        from configurations.runtime
    }

但是什么都没有改变。我找不到输出/libs文件夹。

我该如何将依赖的libs jar包复制到指定的文件夹或路径?


你如何运行代码? - Peter Niederwieser
@PeterNiederwieser Niederwieser首先我运行:gradle build,得到可运行的jar文件 然后,运行jar文件:java -jar XXX.jar - jychan
你可能想使用Sync而不是Copy。另请参阅https://docs.gradle.org/current/userguide/working_with_files.html#sec:sync_task - Morty
8个回答

46

添加:

build.dependsOn(copyToLib)

当运行gradle build时,Gradle会构建任务以及任何依赖该任务的任务(由dependsOn声明)。如果没有设置build.dependsOn(copyToLib),则Gradle不会将复制任务与构建任务关联起来。

因此:

apply plugin: 'java'
apply plugin: 'application'

manifest.mainAttributes('Main-Class': 'com.test.HelloWorld')

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.+'
    )
}

task copyToLib(type: Copy) {
    into "${buildDir}/output/libs"
    from configurations.runtime
}

build.dependsOn(copyToLib)

在SonarQube分析中,在Javacode AST扫描期间,我遇到了ERROR/WARN - 找不到类xx.yy.zz。为了解决这个问题,我必须设置“sonar.java.libraries”,其中包含编译、测试编译和运行时所需的所有jar(依赖项)。我添加了“from configurations.compile from configurations.testCompile from configurations.runtime”。我得到了所有的jar文件在“build/dependent-jars”文件夹中。设置sonar.java.libraries=build/dependent-jars/*.jar后,我没有再遇到错误。感谢gradle将其缓存维护在工作区之外,但使用此代码,我能够在构建文件夹中获取.jar文件。 - AKS

18

我觉得应用程序插件的输出过于冗长而且繁琐。以下是我最终满意的设置方式,即在子目录/ lib 中创建一个包含依赖jar文件的分发zip文件,并将所有依赖项添加到清单文件中的 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://dev59.com/m2Eh5IYBdhLWcg3wNxPM
    //     https://gist.github.com/simon04/6865179
}

本内容托管于 此处

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

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

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

Manifest-Version: 1.0
Main-Class: com.somepackage.MainClass
Class-Path: lib/commons-lang3-3.3.2.jar


8
自Gradle 6.0以来,它变得更加:
tasks {
    val deps by registering(Copy::class) {
        from(configurations.runtimeClasspath)
        into("build/deps")
    }
}

2

所有之前的答案都存在问题,因为它们只收集了一个配置的依赖项。要获取所有依赖项,您应该使用以下内容:

task saveDependencies(type: Copy){
    configurations.each {
        if (it.isCanBeResolved())
            from it into "gradle_dependencies"
    }
    from buildscript.configurations.classpath into "gradle_dependencies"
}

你什么时候想在jar包中包含编译时依赖呢? - Brad Mace
2
@BradMace 我不会将依赖项包含在一个jar文件中,而是将它们复制到一个单独的文件夹中。例如,当您有一堆远程依赖项并且担心某些存储库离线时,您会想要这样做,因此您可以制作一份所有内容的本地副本。 - Fizz Areh

1

Java插件可以将依赖项打包到jar文件中,因此不需要application插件。类似以下的任务即可:

task buildWithDeps(type: Jar) {
    manifest {
        attributes "Main-Class": "com.test.HelloWorld"
    }
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

1
这将创建一个fat jar,问题更多是关于将所有依赖项复制到一个目录中。 - Explorer

1
该应用程序插件要求您按照以下方式设置主类名称:
mainClassName = "com.test.HelloWorld"

你需要将它添加到你的构建脚本中。请记住,如果你想使用 java 命令运行应用程序,你还需要使用 -cp 设置类路径。
应用程序插件通过提供任务 distZip 简化了这个过程。如果你运行该任务,会为你创建一个完整的分发包,位于 build/distributions 下。分发包包含启动脚本和所有依赖项。生成的启动脚本已经为你设置了类路径,因此你不再需要处理它。

1
自至少Gradle 5.6.4起,您需要更接近以下操作。
dependencies {
    implementation 'my.group1:my-module1:0.0.1'
    implementation 'my.group2:my-module2:0.0.1'
}

jar {
    from {
        configurations.compileClasspath.filter { it.exists() }.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

0

对于使用Groovy的Gradle 7.4:

configurations {
    externalLib.extendsFrom(implementation)
}

task copyLibs(type: Copy){
    from configurations.externalLib{
        into '<dest-dir-name>'

        exclude('<if any jars need to be excluded>')
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接