二、依赖管理
在 Go 项目开发中,依赖指各种开发包,依赖包管理是一个非常重要的内容,依赖包处理不好,就会导致编译失败。所以当我们在开发项目时,需要学会利用已经封装好的、经过验证的开发组件或工具来提升自己的研发效率。
为什么需要依赖管理:
当对于hello world以及类似的单体函数只需要依赖原生SDK,而实际工程会相对复杂,我们不可能基于标准库0-1编码搭建,而更多的关注业务逻辑的实现,而其他的框架、日志、driver、以及collection等一系列依赖都会通过sdk的方式引入,这样对依赖包的管理就显得尤为重要。
2.1 Go依赖管理演进
分别经历了三个阶段,分别是GOPATH,Go Vendor和Go Module。目前被广泛应用的是 Go Module,整个演进路线主要围绕实现两个目标来迭代发展:
1、不同环境 (项目) 依赖的版本不同;
2、控制依赖库的版本。
2.1.1 GOPATH
GOPATH是Go语言支持的一个环境变量,value是Go项目的工作区。
目录有以下结构:src:存放Go项目的源码;pkg:存放编译的中间产物,加快编译速度;bin:存放Go项目编译生成的二进制文件。
项目代码直接依赖src下的代码,go get下载最新版本的包到src目录下
GOPATH弊端
例如:A和B依赖于某一package的不同版本。同一个package,有两个不同的版本,A->A()和B->B(),但是src下只能有一个版本存在,所以A项目和B项目无法保证都能编译通过。
因此,在gopath管理模式下,如果多个项目依赖同一个库,则依赖该库的是同一份代码,所以不同项目不能依赖同一个库的不同版本,故无法实现package的多版本控制,这显然不能满足我们的项目依赖需求。为了解决这个问题,Go Vender出现了。
2.1.2 Go Vendor
与GOPATH不同的是,Go Vendor在项目目录下增加了vendor文件,所有依赖包副本形式放在 $ProjectRoot/vendor 下。
依赖寻址方式:vendor => GOPATH
Vendor目录中存放了当前项目依赖的副本。在Vendor机制下,如果当前项目存在Vendor目录,会优先使用该目录下的依赖,如果依赖不存在,就会从GOPATH中寻找,这就导致通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题。但Vendor无法很好的解决依赖包的版本变动问题和一个项目依赖同一个包的不同版本的问题。
Go Vendor弊端
例如:项目A依赖package B和package C,而B和C依赖了D的不同版本,通过vendor的管理模式我们不能很好的控制对于D的依赖版本,一旦更新项目,有可能带来无法控制以来的版本和更新项目可能出现依赖冲突,导致编译出错的问题。
因此,Vendor不能很清晰的标识依赖的版本概念。所以Go Module应运而生。
2.1.3 Go Module
Go Module是Go语言官方推出的依赖管理系统,解决了之前依赖管理系统中存在的诸如无法依赖同一个库的多个版本等问题,Go Module从Go 1.11开始实验性引入,Go 1.16默认开启,一般读为go mod,一种通过go.mod文件管理依赖包版本,另一种通过go get/go mod指令工具管理依赖包。Go Module终极目标为定义版本规则和管理项目依赖关系。
2.2 依赖管理三要素
1、配置文件,描述依赖 go.mod
2、中心仓库管理依赖库 Proxy
3、本地工具 go get/mod