未能理解 Gradle 的默认依赖项解析策略

Failing to understand Gradle's default dependency resolution strategy

我构建了一个 Java 库并将其上传到私有 Artifactory space。假设库的 Gradle 标识符为 com.mycompany:MyLibrary:1.0.0,已上传到 https://artifactory.mycompany.com/artifactory/libs-release and does not exist in JCenter. This library has a dependency on another library which is not uploaded to https://artifactory.mycompany.com/artifactory/libs-release,但可从 JCenter 公开获取。假设第二个库的 Gradle 标识符为 com.google.code.findbugs:jsr305:3.0.0.

作为 Java 应用程序中 Java 库的使用者,我的依赖项列表如下:

dependencies {
    implementation 'com.mycompany:MyLibrary:1.0.0'
}

值得注意的是,我不需要显式声明 com.google.code.findbugs:jsr305:3.0.0 依赖项,因为它将被传递解析。

另外,为了安全起见,我想在JCenter上面订购我的私有Artifactory仓库,如下:

repositories {
    maven {
        url 'https://artifactory.mycompany.com/artifactory/libs-release'
    }
    jcenter()
}

但是,当我尝试构建我的 Java 应用程序时,我遇到了以下错误:

Execution failed for task ':bootJar'.
> Could not resolve all files for configuration ':runtimeClasspath'.
   > Could not find jsr305-3.0.0.jar (com.google.code.findbugs:jsr305:3.0.0).
     Searched in the following locations:
         https://artifactory.mycompany.com/artifactory/libs-release/com/google/code/findbugs/jsr305/3.0.0/jsr305-3.0.0.jar

从这个错误看来,jsr305-3.0.0 工件仅在我的私有 Artifactory 存储库中搜索,而不是在 JCenter 中搜索。如果在我的私有 Artifactory 存储库中找不到 Gradle,我会在 JCenter 中搜索 jsr305-3.0.0 工件。

如果我重新排序存储库以便首先声明 JCenter,如下所示...

repositories {
    jcenter()
    maven {
        url 'https://artifactory.mycompany.com/artifactory/libs-release'
    }
}

...然后构建成功完成。

我遇到的是 Gradle 如何解决依赖关系的预期行为,还是这是一个错误?如果这是预期的行为,我是否可以做些什么来更改依赖项解析策略,以便我可以在 JCenter 之上声明我的私有 Artifactory 存储库?

JCenter 中的元数据优于您的自定义私有 Artifactory 中的元数据space。

Gradle 检查所有存储库以找到最佳元数据并使用它。

查看 Gradle 文档中 Declaring Repositories 页面的以下引述。

首先,来自 Declaring Multiple Repositories 部分:

The order of declaration determines how Gradle will check for dependencies at runtime. If Gradle finds a module descriptor in a particular repository, it will attempt to download all of the artifacts for that module from the same repository. You can learn more about the inner workings of dependency downloads.

其次,来自 Supported Repository Types 部分:

As Gradle prefers to use modules whose descriptor has been created from real meta-data rather than being generated, flat directory repositories cannot be used to override artifacts with real meta-data from other repositories declared in the build.

For example, if Gradle finds only jmxri-1.2.1.jar in a flat directory repository, but jmxri-1.2.1.pom in another repository that supports meta-data, it will use the second repository to provide the module.

事实证明,在过去的某个时刻,我的私有 Artifactory 实例创建了 JCenter 的部分缓存。我不确定这个缓存是怎么来的,但它似乎包含了我的库所依赖的所有工件。此外,缓存仅包括每个工件的 pom 和源 jar 而不是其二进制 jar,如下所示:

那么当我的图书馆的消费者按如下方式订购 his/her 存储库时发生了什么...

repositories {
    maven {
        url 'https://artifactory.mycompany.com/artifactory/libs-release'
    }
    jcenter()
}

... 是 Gradle 在 https://artifactory.mycompany.com/artifactory/libs-release 中找到 com.google.code.findbugs:jsr305:3.0.0 的 pom 文件,并且它期望在那里也找到二进制 jar。当它在那里找不到二进制 jar 时,它会失败构建。请特别注意,如果 Gradle 在它检查过的任何先前存储库中都没有找到它的 pom 文件,它只会继续在列表中的下一个存储库(本例中为 JCenter)中搜索工件.

我的解决方案是从我的私有 Artifactory 实例中删除 JCenter 缓存,或者使缓存完整,以便它包含它所拥有的每个工件的二进制 jar 文件。