这是我参与「第三届青训营 -后端场」笔记创作活动的第2篇笔记。
Go 依赖管理
依赖管理
Go 依赖管理演进
Go 的依赖管理经历了三个阶段,分别是 GOPATH -> Go Vendor -> Go Module。
这三个阶段都是围绕一下两个目的来进行的。
- 不同环境(项目)依赖的版本不同
- 控制依赖库的版本
GOPATH
GOPATH 是 Go 支持的环境变量,所填的值是 Go 的一个工作区目录。
这个目录下有三个关键的目录:
- bin:项目编译的二进制文件
- pkg:项目编译的中间产物
- src:项目源码
GOPATH 实现依赖管理的逻辑是项目代码直接依赖 src 下的代码,通过 go get 下载最新版本的包到 src 下面。
弊端
无法实现 package 的多版本控制
eg:A 和 B 依赖于某一 package 对不同版本

如果 B 不兼容 A 函数,则 A 和 B 同时构建会失败。
Go Vendor
Go Vendor 相比于 GOPATH,只是在项目目录下多一个 vendor 文件夹,所有依赖包副本形式放在 $Projectroot/vendor 下面。
项目的依赖会优先去找 vendor 文件夹,如果没有再去访问 GOPATH。
Go Vendor 通过每一个项目引入一份依赖的副本,解决了多个项目需要同一个 package 依赖冲突的问题。
弊端
- 无法控制依赖的版本
- 更新项目有可能出现依赖冲突,导致编译错误

Go Module
实现了定义版本规则和管理项目依赖关系
- 通过 go.mod 文件管理依赖包版本
- 通过
go get/go mod指令工具管理依赖包
依赖管理三要素
-
配置文件,描述依赖
Go 中对应 go.mod
-
中心仓库管理依赖库
Go 中对应 Proxy
-
本地工具
Go 使用
go get/go mod
依赖配置 - go.mod
在每个包下创建 go.mod 表示这个包是可以被其他人单独的引用的。
go.mod 文件由三部分组成:
-
模块路径:标识了一个模块可以在哪里找到,可以填 URL,也可以填本地目录
module example/project/app
-
原生库:标识依赖的 Go 原生库的一个版本号
go 1.16
-
单元依赖
依赖标识:[Module Path] [Version/Pseudo-version]
Version 的规范有两种:
-
语义化版本
${MAJOR}.${MINOR}.${PATCH}eg: v1.3.0、v2.3.0
-
基于 commit 伪版本
${语义化版本}-${commit的时间戳}-${commit的hash的前缀(12位)}
后面还可能带有一些关键字。
-
indirect:标识间接依赖
假设 A -> B -> C,则 A -> B 是直接依赖,A -> C 是间接依赖。
indirect 用于标识间接依赖,使用时在后面加上
// indirect -
incompatible:标识可能存在不兼容的代码逻辑
主版本 2+ 模块会在模块路径增加 /vN 后缀,类似于下面的 lib5
由于 Go 1.11 才引入 go.mod,对于以前一些仓库可能已经打上了 v2 或更高版本,对于没有 go.mod 文件且主版本 2+ 的依赖,会在后面加上
+incompatible标识,标识可能存在不兼容的代码逻辑。
-

依赖配置 - 依赖图
当同一个项目存在间接依赖版本不一时,Go 会选择最低的兼容版本。
如图,X 项目依赖了 A,B,且 A,B分别依赖了 C 的 v1.3, v1.4 两个版本,最终编译时,会使用 C 的 v1.4 版本。
依赖分发 - 回源
在实际开发中,我们把代码托管到类似于 Github 的代码仓库,虽然在 go.mod 中的依赖中可以直接从对应的仓库下载,但存在很多问题。
-
无法保证构建稳定性
第三方开发者会增加/修改/删除软件版本
-
无法保证依赖可用性
第三方库被删
-
增加平台的压力
Github 的初衷是用来托管代码

依赖分发 - Proxy
对于上述问题,可以使用 Proxy 来解决。
Proxy 会缓存源站中的内容,且内容不会改变,即使源站已经删除。

依赖分发 - 变量 GOPROXY
go.mod 通过 GOPROXY 环境变量来控制 Proxy 的配置。
GOPROXY 的值是字符串形式的 URL 列表,用逗号分隔。
//服务站点 URL 列表,direct 表示 源站
GOPROXY = "https://proxy1.cn, https://proxy2.cn, direct"
工具 - go get
使用 go get example.org/pkg 拉取依赖
@update默认是这个,拉取 major 最新版本@none删除依赖@v1.1.2tag 版本,语义化版本@23dfdd5特定的 commit@master分支的最新 commit
工具 - go mod
init初始化,创建 go.mod 文件download下载模块到本地缓存tidy增加需要的依赖,删除不需要的依赖