这是我参与「第五届青训营」伴学笔记创作活动的第 3 天
演进路线
背景:
- 工程项目不可能基于标准库从 0 到 1 编码搭建。
- 需要一种方式管理依赖包。
Go 依赖管理的演进:
- GOPATH
- Go Vendor
- Go Module
GOPATH:
-
在环境变量
$GOPATH下有三个文件夹:bin项目编译的二进制文件pkg项目编译的中间产物,加速编译src项目源码
-
项目代码直接依赖
src下的代码。 -
通过
go get命令下载最新版本的包到src目录下。 -
弊端:无法实现依赖包的多版本控制。
Go Vendor:
- 项目目录下增加
vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor下。 - 优先从项目目录下的
vendor中寻找依赖,未找到再从GOPATH中找。 - 通过每个项目引入一份依赖的副本,解决了多个项目需要同一个
package依赖的不同版本的冲突问题。 - 弊端:无法控制依赖的版本;更新项目又可能出现依赖冲突,导致编译出错。
Go Module
终极目标:定义版本规则和管理项目依赖关系。
- 通过
go.mod文件管理依赖包版本(类似Java使用Maven进行依赖管理时的pom.xml) - 通过
go get或go mod指令管理依赖包
完备的依赖管理的三要素:
配置文件
go.mod文件:
module example-app // 依赖管理基本单元, 声明模块名
go 1.19 // 此模块的 go 标准库版本
require ( // 依赖库
example/lib1 v1.0.2
example/lib2 v1.0.0
example/lib3 v0.1.0-20190725025543-5a5fe074e612
example/lib4/v3 v3.0.2
example/lib5/ v3.2.0+incompatible
)
对于每个依赖,都由依赖标识进行描述:[Module Path] [Version/Pseudo-Version] 关于Version:
- 语义化版本:
${Major}.${Minor}.${Patch},例如1.3.0。 - 基于
commit的伪版本,vX.X.X-yyyymmddhhmmss-abcdef123456,版本号-时间戳-十二位哈希码。 - 主版本 2+ 的模块会在模块路径里增加
/vN后缀。 - 对于没有
go.mod文件并且主版本 2+ 的依赖,会加+incompatible。
依赖分发
主要解决依赖去哪里下载的问题。如果直接从Github、SVN等平台下载的话:
- 无法保证构建稳定性,依赖作者可能增加/修改/删除版本。
- 无法保证依赖可用性。
- 增加代码托管平台的压力。
因此采用Proxy缓存源站的依赖,开发者从Proxy下载依赖,保证稳定可靠。 通过环境变量GOPROXY配置:
GOPROXY="https://proxy1.cn, https://proxy2.cn, direct"
配置服务站点 URL 列表,direct表示源站。下载依赖时会依次从各个 URL 站点查找,如果没找到再去下一个站点,最后到源站。
工具
使用go get命令工具拉取依赖。
go get example.org/pkg
在命令最后增加特定语句进行特定操作:
@update默认,即拉取依赖。@none删除依赖。@v1.1.2tag版本,语义版本。@23dfdd5特定的commit。@master分支的最新commit。
使用go mod对项目进行依赖管理。
go mod init # 初始化项目
go mod download # 下载 go.mod 文件中指定的依赖到本地缓存
go mod tidy # 根据 go.mod 文件更新依赖(增加需要的依赖,删除不需要的依赖)