为什么需要依赖管理?
最早的时候,Go所依赖的所有的第三方库都放在GOPATH这个目录下面。这就导致了同一个库只能保存一个版本的代码。如果不同的项目依赖同一个第三方的库的不同版本,应该怎么解决?
Go Module 是在 golang 1.11中加入的一个依赖管理工具,在golang 1.11中需要通过设置环境变量export GO111MODULE=on来开启这个功能,到了golang 1.13开始之后就成为了golang默认的依赖管理工具了
GOPATH
.
├── bin
│ ├── glide
│ ├── gocode
│ ├── ...
├── pkg
│ └── linux_amd64
└── src
├── github.com
└── gopkg.in
├── workspace
│ ├── project1
│ │ ├── .git
│ │ ├── main.go
│ ├── project2
目录下存放相应的代码
- bin:一般用于存放可执行文件
- pkg:存放静态连接库文件
- src:存放第三方依赖的源码和自己开发的代码
但是GOPATH存在一些问题
例如 我们启动一个项目,如果其中有A一来a,那么本地就会go get a这个依赖,此时依赖版本仍为1.0.1 但是当时间过的够久之后,你又添加了一个业务C,C同时依赖a这个依赖,但是C依赖的是a最新的版本,所以呢,正常运行的时候去拉取依赖的时候发现本地有,所以就不会去拉取最新版本的了,导致不能正常运行从而报错
而且等到时间够久后,如果出现某些情况,需要业务升级,版本之间又不能够适配了,那么就会再次出现点问题
那么说明这个GOPATH问题其实还是挺大的哈
那么后续就会有其它的解决这个依赖的方案 我们来看看后面的
Go Vendor依赖管理
.
├── main.go
└── vendor/
├── github.com/
│ └── astaxie/
│ └── beego/
└── golang.org/
└── x/
└── net/
多了一个vendor目录
在 Go 的 vendor 机制中,可以使用 vendor/vendor.json 来进行包和版本管理。同时,govendor 提供了一系列命令用于项目中的依赖管理。以下是一些常用命令及其功能:
govendor init:初始化vendor,在项目根目录创建vendor文件夹和vendor/vendor.json文件。govendor add +external:将项目中引用的外部依赖从$GOPATH拷贝到vendor目录。govendor add gopkg.in/yaml.v2:从$GOPATH拷贝指定包到vendor目录。govendor list:列出项目引用的所有依赖包。govendor list -v fmt:列出一个包及其引用的列表。govendor fetch golang.org/x/net/context:从远程下载依赖包,不会添加到$GOPATH。govendor fetch golang.org/x/net/context@v1:从远程下载指定版本的依赖包。govendor fetch golang.org/x/net/context@=v1:从远程下载特定的 tag 或 branch。govendor test +local:测试项目中的测试用例。govendor fetch +out:拉取所有依赖到vendor目录。govendor update +vendor:从$GOPATH更新vendor中的依赖。govendor sync:同步vendor.json中的依赖信息。
vendor 机制的缺点
虽然 vendor 目录解决了一部分依赖版本管理的问题,但仍存在一些不足之处:
- 目录限制:
vendor机制要求项目必须在$GOPATH/src目录下使用,这与$GOPATH的限制一致。 - 存储冗余:之前
$GOPATH中的依赖是多个项目共享的,而使用vendor机制后,每个项目都需维护自己的一套依赖,导致存储空间增大。因此,在推送代码到远程仓库时,通常不推送vendor目录中的依赖包,而是通过vendor.json保持依赖定义,以便他人拉取项目代码后可以自行下载依赖。 - 手动管理繁琐:虽然
vendor提供了一些依赖管理命令,但大部分情况下依然需要手动处理依赖的版本、获取和存储等问题。
为了解决这些问题,Go 官方在 1.11 版本引入了 Go Module 来替代 vendor 机制进行依赖管理,进一步简化和优化了依赖管理体验。
GOMOD
go module是Go1.11版本之后官方推出的版本管理工具,并且从Go1.13版本开始,go module将是Go语言默认的依赖管理工具。
Go Module是基于package的,package就是由一个文件或者多个文件实现的单一功能,在一个项目当中,会包含一个或多个package;
package包,这个特性是实现这一个技术的关键
一个Go Module就是一个项目中这些package的集合,它们可以组成一个独立的版本单元,它们可以一起打版本,发布和分发;在根目录下面有go.mod文件,定义了module path和依赖的版本
在Go语言中,"module" 是指一个独立的包管理单元,包含了一个 go.mod 文件,该文件定义了项目的依赖关系以及其他模块管理的属性。通常情况下,一个Go项目只有一个模块,即只有一个 go.mod 文件位于项目的根目录。
项目的主文件夹通常包含 go.mod 文件,并且可能包含源代码文件。子文件夹可以定义自己的包(package),而项目的根文件夹也可能被定义为一个包。这是Go语言项目中最常见的结构。
然而,也有可能一个项目中包含多个模块,即在一个项目的不同子目录中分别包含多个 go.mod 文件。每个模块都管理自己的依赖和包。这种结构在Go项目中较为少见,通常用于大型项目,其中不同的模块可能需要不同版本的依赖,或者需要更细粒度的依赖管理。这种方式可以使项目的不同部分相对独立,有利于大团队开发和管理复杂项目。
常用的go mod命令如下:
go mod download 下载依赖的module到本地cache(默认为$GOPATH/pkg/mod目录)
go mod edit 编辑go.mod文件
go mod graph 打印模块依赖图
go mod init 初始化当前文件夹, 创建go.mod文件
go mod tidy 增加缺少的module,删除无用的module
go mod vendor 将依赖复制到vendor下
go mod verify 校验依赖
go mod why 解释为什么需要依赖
简单的使用gomod
1.set GO111MODULE=on
2.SET GOPROXY=goproxy.cn (这是win环境下的) export GOPROXY=goproxy.cn (这是mac环境下的)
3.go mod init [包名] // 初始化项目(如果你是初始化项目直接 go mod init 就好了)
4.在你的目录文件下会生成go.mod和go.sum文件 go.mod 里面包含了你的所有的包!
5.在文件里面引入包名的时候有的编辑器会报错但是是可以正常编译的
6.下载包使用go get
7.修改包的版本号直接去go.mod文件修改然后go mod download