这是我参与「第五届青训营 」伴学笔记创作活动的第 7 天
前言
大家好呀,这是我参加青训营伴学笔记创作活动的第 7 天,如存在问题,烦请各位斧正!
其中有一些关键图片超过了最大字符限制,不能上传了,我都使用特殊标记给它标记出来了,如有需要,请联系我。
Go依赖管理经历了三个重要的阶段:GOPATH -> vendor -> Go Module
GOPATH
1、环境变量GOROOT&GOPATH
1)安装完golang后,有两个路径GOROOT和GOPATH。 去环境变量自己配置GOPATH的值,项目和第三方包都放在这。
使用命令 go env 查看这两个路径:
GOROOT="/usr/local/go"和GOPATH="/home/zhanhzhong/go"2)实际上Go语言项目是由一个或多个package组成的,这些package按照来源分为以下几种:
(1)标准库:标准库的package全部位于GOROOT环境变量指示的目录中。
(2)第三方库 和 项目私有库:第三方库和项目私有库都位于GOPATH环境变量所指示的目录中。
3)第三方库和自己写的项目都需要放在GOPATH的src目录下,
而且需要使用go get命令来逐个下载第三方库(go get命令自动把第三方库下载到GOPATH/src目录)。
2、依赖查找
1)当某个package需要引用其他包时,编译器就会依次在下面的目录查找:
GOROOT/src/ 和 GOPATH/src/
2)如果某个包从GOROOT下找到的话,就不再到GOPATH目录下查找,所以如果项目中开发的包名与标准库相同的话,将会被自动忽略。
3、GOPATH的缺点
1)GOPATH的优点是足够简单,但由于不同项目的第三方库都存放在同一个目录下,
而且同一个第三方库只能存放某一个版本,不能同时存放多个版本,因此不能很好的满足实际项目的工程需求。
2)针对GOPATH的缺点,GO语言社区提供了Vendor机制,从此依赖管理进入第二个阶段:将项目的依赖包私有化。
vendor
自Go 1.6版本起,vendor机制正式启用,它允许把项目的依赖全部放到一个位于本项目的vendor目录中,
这个vendor目录可以简单理解成私有的GOPATH目录。(但是vendor放进项目目录也会导致它随着git上传到远端,比较臃肿)
1、依赖查找
1)编译时,优先从vendor中寻找依赖包,如果vendor中找不到再到GOPATH中寻找。顺序如下:
Main.go所在目录下的vendor目录
再上一个层级的目录下的vendor目录
…
GOROOT/src/
GOPATH/src/
2)可见一个项目里可以有多个vendor目录,但是一般建议只集中维护一个vendor目录。
2、vendor的缺点
1)vendor很好的解决了多项目间的隔离问题,但是位于vendor中的依赖包无法指定版本,
某个依赖包,在把它放入vendor的那刻起,它就固定在当时版本,项目的其他开发者很难识别出你所使用的依赖版本。
2)比起这个,更严重的问题是二进制急剧扩大问题,比如你依赖某个开源包A和B,但A中也有一个vendor目录,其中也放了B,
那么你的项目中将会出现两个开源包B。再进一步,如果这两个开源包B版本不一致呢?如果二者不兼容,那后果将是灾难性的。
3)一直到Go 1.11版本,官方社区推出了Modules机制,从此Go的版本管理走进第三个时代。
Go Module
1、概述
1)它基本上完全解决了GOPATH和vendor时代遗留的问题。
2)Go Module是一种全新的依赖管理方案,它涉及一系列的特性,但究其核心,它主要解决两个重要的问题:
(1)准确的记录项目依赖:(依赖哪些package、以及package的版本)
比如你的项目依赖github.com/prometheus/client_golang, 且必须是v1.0.0版本,
那么你可以通过Go Module指定,任何人在任何环境下编译你的项目, 都必须要使用github.com/prometheus/client_golang的v1.0.0版本。
(2)可重复的构建:(一旦项目的依赖被准确记录了,就很容易做到重复构建)
项目无论在谁的环境中(同平台)构建,其产物都是相同的。(避免出现“我这运行没问题,肯定是你环境问题”等类似问题出现。)
3)依赖管理三要素 以及在go中的体现:① 配置文件,描述依赖go. mod ② 中心仓库管理依赖库Proxy ③ 本地工具go get/mod
2、go mod指令
(1)
go mod init(生成 go.mod 文件)(2)
go mod download(下载 go.mod 文件中指明的所有依赖)(3)
go mod tidy(整理现有的依赖)(4)
go mod graph(查看现有的依赖结构)(5)
go mod edit(编辑 go.mod 文件)(6)
go mod vendor(导出项目所有的依赖到vendor目录)(7)
go mod verify(校验一个模块是否被篡改过)(8)
go mod why(查看为什么需要依赖某模块)
3、go.mod文件介绍
<超过最大字符数限制图片>
1)第一个也就是模块的路径,用来标识一个模块。如果一个项目每个包都想被单独引用,那每个包都要建立一个go.mod文件。
2)第二个定义go原生库的版本。最后一个是引入依赖与版本的唯一标识。
(版本号:V1.1.1 第一个1表大版本 不同大版本不兼容,第二个表新增、修改功能 同一个大版本下兼容, 最后一个表修复bug等)
(1)indirect表示这个依赖是间接依赖,不是直接导入的。
(2)incompatible关键字表示可能存在不兼容的代码逻辑
(3)基于commit的版本:每次提交代码或提交commit,go都会默认生成一个伪版本号,就像这样:
vX.0.0-yyyymmddhhmmss-abcdefgh1234(中间是日期,最后12位是哈希码)
4、go的Proxy(中心仓库)
1)可以防止有时候作者把github的依赖删除了等情况。保证了依赖管理的可靠和稳定。
2)它是配置的一个go环境变量,一个URL列表,最后的direct表示如果这些URL都没有 则会回源到第三方代码平台上找依赖。
Goproxy=https://proxy1.cn,https://proxy2.cn,direct
5、go get指令
1)
go get example.com/pkg(为包添加依赖项或将其升级到最新版本)2)
go get example.com/pkg@v1.2.3(将一个包升级或降级到特定版本)3)
go get example.com/mod@none(删除对某个模块的依赖,并将需要它的模块降级)4)使用
go env查看目前配置的环境变量。5)使用以下代码修改国内镜像:
go env -w GOPROXY=https://goproxy.cn