这是我参与「第五届青训营」伴学笔记创作活动的第 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.2
tag版本,语义版本。@23dfdd5
特定的commit。@master
分支的最新commit。
使用go mod
对项目进行依赖管理。
go mod init # 初始化项目
go mod download # 下载 go.mod 文件中指定的依赖到本地缓存
go mod tidy # 根据 go.mod 文件更新依赖(增加需要的依赖,删除不需要的依赖)