这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
前言
本文主要介绍Go
语言依赖管理的演进路线以及Go Module
实践。
这里的依赖指的是在开发过程中用到的各种开发包,使用别人开发好的组件、工具来提升自己的开发效率。
背景
在使用Go
编写一些简单的单体函数时,不需要引入别的依赖,仅使用SDK
内置功能即可完成日常开发。
但在实际项目的开发中,功能相对比较复杂,我们不可能只使用SDK
标准库从0到1来完成开发,这样会累死人的,老板也不愿意。我们可以利用别人开发好的工具、框架等引入我们的项目中,避免重复造轮子。
随着依赖的增多,依赖管理越发重要。
依赖管理
Go
的依赖管理主要分为3种:GOPATH
、Go Vendor
、Go Module
,其中Go Module
最为常用。
出现3种主要目的是围绕2个方面:不同环境(项目)依赖的版本不同、控制依赖库的版本。
GOPATH
GOPATH
是Go
支持的一个环境变量,他是Go
项目的工作区,有三个关键点:
- bin 项目编译的二进制文件
- pkg 项目编译的中间产物,加速编译
- src 项目源码
GOPATH
依赖指的是项目代码直接依赖src
下的代码,通过go get
下载最新版本的依赖包到src
目录下。
弊端
无法实现package的多版本控制。
Go Vendor
Go Vender
的出现解决了GOPATH
不能多版本控制的问题。
Go Vender
依赖管理模式在项目目录下增加vendor
文件,所有依赖包副本形式放在$ProjectRoot/vendor
目录下,其依赖寻址方法为vendor
=>GOPATH
。
Go Vender
通过每个项目引入一份依赖的副本方式,解决了多个项目需要同一个package
依赖的冲突问题。
弊端
Go Vender
存在以下问题:
- 无法控制依赖的版本
- 更新项目又可能出现依赖冲突,导致编译出错。
出现这样问题的原因归根结底还是因为直接依赖的是项目的源码,不能清晰标识版本的概念。
Go Module
Go Module
的出现解决了Go Vender
出现的问题,可以管理依赖的版本。
Go Module
通过go.mod
文件管理依赖包的版本,通过go get
/go mod
指令工具管理依赖包。
Go Module
的终极目标为:定义版本规则和管理项目的依赖关系。
依赖管理三要素
依赖管理存在以下三要素:
- 配置文件,描述依赖 go.mode
- 中心仓库管理依赖库 Proxy
- 本地工具 go get/mod
go.mod
下面通过一个例子来看下go.mod
文件配置:
module example/project/app 依赖管理基本单元
go 1.16 原生库
require( 单元依赖
example/lib1 v1.0.2
example/lib2 v1.0.0
example/lib3 v0.1.0-20190725
example/lib4 v0.0.0-20180036
example/lib5/v3 v3.0.2
example/lib6 v3.2.0+incompatible
)
复制代码
依赖标识:[Module Path][Version/Pseudo+version]
module
为模块路径,用来标识一个模块,可以根据这个来找到模块,依赖托管的路径。
go
为项目依赖原生库的版本号。
require
为最关键的一部分,主要是描述单元依赖,主要由两部分组成:Module Path
、Version/Pseudo+version
。
版本定义
go.mod
版本主要有两种类型:语义化版本、基于commit伪版本。
语义化版本
组成形式:${MAJOR}.${MINOR}.${PATCH}
示例:V1.3.0、V2.3.0
基于commit伪版本 组成形式:vx.0.0-yyyymmddhhmmss-abcdefgh1234
示例:v0.0.0-20220401081311-c38fb59326b7、v1.0.0-20201130134442-10cb98267c6c
indirect
如果不是直接依赖的模块,用indirect
标识出来。
假如依赖关系为:A->B->C
,其中A->B
为直接依赖,A->C
为间接依赖。
incompatible
在依赖后面加上incompatible
,代表代码中可能存在不兼容的问题。
Go
在处理版本兼容的问题时,会选择最低的兼容版本。
Proxy
依赖是从哪里下载的呢?
比较常见的是GitHub
,GitHub
是一个代码托管平台,但是访问的时候可能存在不稳定性的问题,所以使用代码托管平台下载依赖的话会存在以下几个问题:
- 无法保证构建稳定性,可能存在增加、修改、删除软件版本。
- 无法保证依赖可用性,软件被删除
- 增加第三方压力,代码托管平台负载问题
为了解决这些问题,就出现了Proxy
这个概念。
Proxy
是一个中间站点,他会缓存软件版本的内容,而且缓存的版本不会改变。
通过Proxy
可以保证站点的稳定性、可靠性。
Proxy配置
设置环境变量GOPROXY
GOPROXY="https://proxy1.cn,https://proxy2.cn,direct"
复制代码
可以配置多个url
用逗号分隔,direct代表源站。
在获取依赖时,会从前往后依次查找依赖。
go get
使用示例:go get example.org/pkg + 参数
参数示例:
- @update 默认参数
- @none 删除依赖
- @v1.1.2 指定tag版本,语义版本
- @23dfdd5 特定的commit版本
- @master 指定分支的最新commit
附加参数:
- -d 只下载不安装
- -f 只有在你包含了 -u 参数的时候才有效,不验证
- -fix 在获取源码之后先运行 fix,然后再去做其他的事情
- -t 同时也下载需要为运行测试所需要的包
- -u 强制使用网络去更新包和它的依赖包
- -v 显示执行的命令日志信息
go mod
使用示例:go mod + 参数
常用参数如下:
- download 下载依赖的到本地
- edit 编辑go.mod文件
- graph 打印模块依赖图
- init 初始化当前文件夹, 创建go.mod文件 go mod tidy 拉取缺少的模块,移除不用的模块 go mod vendor 将依赖复制到vendor下 go mod verify 验证依赖是否正确 go mod why 解释为什么需要依赖
总结
本文主要介绍Go
语言依赖管理的演进路线以及Go Module
实践。