关于gradle中plugins依赖未走私服导致编译失败的原因探析
# 背景
我们的项目标配使用gradle
进行编译,我们也配置了nexus
作为私服,理论上来说,不应该再会出现因包依赖的原因导致编译失败的情况,但是这个问题仍旧会偶尔发生,我解决过一两次,只看到通常失败的编译都是在开头的时候去 plugins.gradle.org
拉包的情况,当时将该问题存疑,今天特来探析一下导致这个问题的根因。
# 摸索
简单分析: 理论上来说,当我们的gradle
通过build.gradle
将repositories
指向私服地址之后,就不应该再出现任何一个第三方的私服地址才对,但 gradle 在这里就是异常头铁,偏偏会在开头请求一下官方地址。这是彼时遇到问题之后的一个原始的疑问!
缘起: 今天一位开发同学反馈说某项目在gray环境
打包的时候出现编译失败的情况。我看到构建日志如下:
+ gradle --no-daemon bootJar
FAILURE: Build failed with an exception.
* What went wrong:
A problem occurred configuring root project 'example'.
> Could not resolve all artifacts for configuration ':classpath'.
> Could not resolve org.springframework.boot:spring-boot-gradle-plugin:2.1.5.RELEASE.
Required by:
project : > org.springframework.boot:org.springframework.boot.gradle.plugin:2.1.5.RELEASE
> Could not resolve org.springframework.boot:spring-boot-gradle-plugin:2.1.5.RELEASE.
> Could not parse POM https://plugins.gradle.org/m2/org/springframework/boot/spring-boot-gradle-plugin/2.1.5.RELEASE/spring-boot-gradle-plugin-2.1.5.RELEASE.pom
> Could not resolve org.springframework.boot:spring-boot-tools:2.1.5.RELEASE.
> Could not resolve org.springframework.boot:spring-boot-tools:2.1.5.RELEASE.
> Could not get resource 'https://plugins.gradle.org/m2/org/springframework/boot/spring-boot-tools/2.1.5.RELEASE/spring-boot-tools-2.1.5.RELEASE.pom'.
> Could not HEAD 'https://plugins.gradle.org/m2/org/springframework/boot/spring-boot-tools/2.1.5.RELEASE/spring-boot-tools-2.1.5.RELEASE.pom'.
> Remote host closed connection during handshake
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
通常遇到这种问题,我都会到对应构建的 Jenkins 服务器上,手动跑一次编译,然后 ci 机器再次打包就能过去了。这次使用同样手法将问题解决之后,我打算探究一下导致该问题的根因是什么。
后来了解到运维侧在打包的机器上有一个定时清理本地缓存的操作,是为了避免一些包依赖不更新的问题。所以当缓存清空之后,这些依赖就会重新下载,就可能因为网络原因而失败。
首先看到了报错提示的包基本都是 plugins,于是看了一眼 build.gradle 文件,可以看到在文件中有这样的配置声明:
plugins {
id 'org.springframework.boot' version '2.1.5.RELEASE'
id 'java'
}
2
3
4
报错的提示也正是在拉取该插件的时候报错的。
所以,这里得到一个问题是:即便已经配置指向了私服,但是此处的 plugins 中的包拉取的时候仍旧绕过了私服。
这是为什么呢?
通过 Google,找到了官方文档 (opens new window) 对 plugins 功能的介绍,并且里边也介绍了plugins 的仓库指向 (opens new window),需要通过单独的配置文件进行配置:
$ cat settings.gradle # 注意需要把配置文件放到这个文件的开头,而非build.gradle中
pluginManagement {
repositories {
maven {
url './maven-repo'
}
gradlePluginPortal()
ivy {
url './ivy-repo'
}
}
}
2
3
4
5
6
7
8
9
10
11
12
这里我做了下测试,将如下配置添加到了项目对应的配置中:
$ cat settings.gradle
pluginManagement {
repositories {
//本地资源库
mavenLocal()
//自定义maven仓库
maven {
name 'aifocus-repository'
url 'http://nexus.eryajf.net/nexus/content/groups/public/'
}
}
}
......
2
3
4
5
6
7
8
9
10
11
12
13
14
接着执行构建,发现如下报错:
FAILURE: Build failed with an exception.
* Where:
Build file '/data/gradle/example/build.gradle' line: 2
* What went wrong:
Plugin [id: 'org.springframework.boot', version: '2.1.5.RELEASE'] was not found in any of the following sources:
- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (could not resolve plugin artifact 'org.springframework.boot:org.springframework.boot.gradle.plugin:2.1.5.RELEASE')
Searched in the following repositories:
MavenLocal(file:/root/.m2/repository)
aifocus-repository(http://nexus.eryajf.net/nexus/content/groups/public/)
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 3s
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在私服仓库中,找不到这个包,需要注意的是,虽然通过org.springframework.boot
能够搜索到包,但是这个包还有gradle.plugin
的 path,所以如下检索到的包并不符合条件。
那么就需要将官方地址代理进来,此处要注意一个坑点在于,官方代理的正确地址是 https://plugins.gradle.org/m2/ 而非 https://plugins.gradle.org ,此处踩坑可见该帖子 (opens new window)。
国内一些镜像库也有 plugin 的镜像,所以这里直接配置了阿里的镜像仓库:https://maven.aliyun.com/repository/gradle-plugin/
当我把官方地址加入到私服之后,再次回来进行构建,可以看到这个插件通过我们的私服进行拉取了,而正确拉取之后,私服当中也缓存了该依赖,符合预期,喜大普奔!
# 结论
这个问题以后就变得简单了,所有使用 gradle 打包的项目,只要使用到了 plugins,那么就应该在 settings.gradle 文件的开头,加上如下配置:
pluginManagement {
repositories {
//本地资源库
mavenLocal()
//自定义maven仓库
maven {
name 'aifocus-repository'
url 'http://nexus.eryajf.net/nexus/content/groups/public/'
}
}
}
2
3
4
5
6
7
8
9
10
11
从此不会再有与 plugins.gradle.org 这个域名交互的情况出现,自然也与编译失败说拜拜了!