前言: 在Golang1.11之前的版本中,官方没有提供依赖和包管理工具。开发者通常会使用
vendor
或者glide
的方式来管理依赖(也有直接使用GOPATH多环境方式),而在Golang1.11之后官方终于出了名为go modules
的版本管理机制。
注意:
export GO111MODULE=on
来显式开启go module 初始化项目
# 在GOPATH之外创建一个项目目录
➜ mkdir cmdb-job
# 进入目录后初始化一个module
➜ cd cmdb-job
➜ go mod init cmdb-job
go: creating new go.mod: module cmdb-job
# 查看生成的mod.md
➜ cat go.mod
module cmdb-job
go 1.12
# 使用第三方模块编写一丢丢代码逻辑
# 一个字符串简单几种加密方式的简单工具
➜ cat main.go
/*================================================================
*Copyright (C) 2019 BGBiao Ltd. All rights reserved.
*
*FileName:main.go
*Author:BGBiao
*Date:2019年09月07日
*Description:
*
================================================================*/
package main
import (
"fmt"
"github.com/xxbandy/go-utils/crypto"
)
func main() {
fmt.Println(crypto.Md5("hello"))
fmt.Println(crypto.Hmac("key2", "hello"))
fmt.Println(crypto.Sha1("hello"))
fmt.Println(crypto.HmacSha1("key2", "hello"))
}
# 查看下项目结构和依赖
➜ tree -L 1 .
.
├── go.mod
├── go.sum
└── main.go
测试运行项目
# 测试运行
# 第一次运行会自动检查代码里的第三方依赖包,并下载和接下项目依赖的包
➜ go run main.go
go: finding github.com/xxbandy/go-utils/crypto latest
go: finding github.com/xxbandy/go-utils latest
go: downloading github.com/xxbandy/go-utils v0.0.0-20190506113112-d88d469a26b2
go: extracting github.com/xxbandy/go-utils v0.0.0-20190506113112-d88d469a26b2
5d41402abc4b2a76b9719d911017c592
f1b90b4efd0e5c7db52dfa0efd6521a3
aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
79806c50bab4825a371e3c4fff80bae0c731d54e
# 第二次运行
➜ go run main.go
5d41402abc4b2a76b9719d911017c592
f1b90b4efd0e5c7db52dfa0efd6521a3
aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
79806c50bab4825a371e3c4fff80bae0c731d54e
# 查看管理mod的依赖配置
## go.mod会记录项目所需依赖以及具体的版本号记录(go-utils这个库没有版本,所以会根据提交日期和commitid来唯一标识版本)
➜ cat go.mod
module cmdb-job
go 1.12
require github.com/xxbandy/go-utils v0.0.0-20190506113112-d88d469a26b2 // indirect
## go.sum文件会记录依赖树的详细信息
➜ cat go.sum
github.com/xxbandy/go-utils v0.0.0-20190506113112-d88d469a26b2 h1:SD6OuR8EUvCmiBDoxItcFYXIMuse45HvuSh3ho0AAeU=
github.com/xxbandy/go-utils v0.0.0-20190506113112-d88d469a26b2/go.mod h1:XhyyBI KH4XEIbw3EhMFjZfJcV3kDK4iSAT7zZYd Uc=
注意:go mod 还有一些其他比较有意思的工具,比如可以打印依赖树,比如可以查看哪些模块在哪些包引用了
go mod的其他特性
# 执行go help mod可以查看到以下子命令
➜ go help mod
download download modules to local cache # 下载模块包到本地缓存
edit edit go.mod from tools or scripts # 从工具或脚本中修改go.md内容(暂时没觉得很好用)
graph print module requirement graph # 打印模块依赖树
init initialize new module in current directory # 在当前目录初始化一个模块
tidy add missing and remove unused modules # 添加或略或删除不使用的包
vendor make vendored copy of dependencies # 将依赖拷贝到vendor中(会将依赖打包到当前目录下的vendor目录)
verify verify dependencies have expected content # 检查依赖内容
why explain why packages or modules are needed # 解释为什么哪些包或者模块被需要
# 查看当前项目的依赖树(项目复杂时比较有用)
➜ go mod graph
cmdb-job github.com/xxbandy/[email protected]
# 查看模块或包在哪里被依赖了
➜ go mod why github.com/xxbandy/go-utils/crypto
# github.com/xxbandy/go-utils/crypto
cmdb-job
github.com/xxbandy/go-utils/crypto
# 拷贝一份依赖到项目本地
# 会将项目的依赖包拷贝到项目的vendor目录中
➜ go mod vendor
➜ tree -L 3 .
.
├── go.mod
├── go.sum
├── main.go
└── vendor
├── github.com
│ └── xxbandy
└── modules.txt
注意:
这个时候可能会有人有疑问了,既然go mod vendor
将依赖拷贝一份到项目家目录的vendor
目录了,那原始的依赖存在哪里?比如我们之前没有依赖管理之前,默认的依赖都是在$GOPATH/src/
下面的
其实,在使用了go mod
之后,项目依赖的全部依赖包都会在$GOPATH/pkg/mod/cache/download/
中统一缓存下来,而项目中的go.md
中会记录真正的版本信息,去缓存中引用即可。
# 查看go mod之后缓存的依赖包
➜ tree -L 3 ${GOPATH}/pkg/mod/cache/download/
${GOPATH}/pkg/mod/cache/download/
└── github.com
└── xxbandy
└── go-utils
一个开源项目示例
我们就以golang-gin-vue项目为例来看下go mod
的一些功能吧.
golang-gin-vue
是一个使用gin框架编写后端接口,结合vue来渲染前端的一个示例项目.
# 克隆项目到本地
➜ git clone https://github.com/xxbandy/golang-gin-vue.git
➜ cd golang-gin-vue
# 使用go mod初始化项目
➜ golang-gin-vue git:(master) go mod init golang-gin-vue
go: creating new go.mod: module golang-gin-vue
# 初始化后会默认生成go.mod文件,但是不会加载依赖包,需要go run或者go build来自动加载依赖
➜ golang-gin-vue git:(master) ✗ go build main.go
go: finding github.com/gorilla/mux v1.7.3
go: downloading github.com/gorilla/mux v1.7.3
go: extracting github.com/gorilla/mux v1.7.3
# 查看go.mod文件
➜ golang-gin-vue git:(master) ✗ cat go.mod
module golang-gin-vue
go 1.12
require (
github.com/gin-gonic/gin v1.4.0 // indirect
github.com/gorilla/mux v1.7.3 // indirect
)
# 打印依赖树关系
## 基本上可以知道项目和库依赖了哪些库
➜ go mod graph
golang-gin-vue github.com/gin-gonic/[email protected]
golang-gin-vue github.com/gorilla/[email protected]
github.com/gin-gonic/[email protected] github.com/gin-contrib/[email protected]
github.com/gin-gonic/[email protected] github.com/golang/[email protected]
github.com/gin-gonic/[email protected] github.com/json-iterator/[email protected]
github.com/gin-gonic/[email protected] github.com/mattn/[email protected]
github.com/gin-gonic/[email protected] github.com/modern-go/[email protected]
github.com/gin-gonic/[email protected] github.com/modern-go/[email protected]
github.com/gin-gonic/[email protected] github.com/stretchr/[email protected]
github.com/gin-gonic/[email protected] github.com/ugorji/[email protected]
github.com/gin-gonic/[email protected] golang.org/x/[email protected]
github.com/gin-gonic/[email protected] gopkg.in/go-playground/[email protected]
github.com/gin-gonic/[email protected] gopkg.in/go-playground/[email protected]
github.com/gin-gonic/[email protected] gopkg.in/[email protected]
github.com/stretchr/[email protected] github.com/davecgh/[email protected]
github.com/stretchr/[email protected] github.com/pmezard/[email protected]
github.com/stretchr/[email protected] github.com/stretchr/[email protected]
github.com/mattn/[email protected] golang.org/x/[email protected]
gopkg.in/[email protected] gopkg.in/[email protected]
golang.org/x/[email protected] golang.org/x/[email protected]
golang.org/x/[email protected] golang.org/x/[email protected]
golang.org/x/[email protected] golang.org/x/[email protected]
# 查看gin这个模块被哪里需要(golang-gin-vue项目和gin框架本身需要)
➜ go mod why github.com/gin-gonic/gin
# github.com/gin-gonic/gin
golang-gin-vue
github.com/gin-gonic/gin
我们在使用Golang
进行开发过程中,通常会发现各种第三方库会依赖golang.org/x
之类的原生库,或者一些其他国外大厂提供的共有库,由于政策原因,我们是无法直接访问国外网站来下载依赖库的(网速也有限制),因此在开发过程中也是比较头疼的. 这个时候通常大家都会去采用科学上网,或者通过一些代理的方式来解决. 而在Golang
高版本中,包含了goproxy
特性,用户可以直接指定代理来下载依赖的第三方库,一方面解决了下载速度的问题,另外一方面也解决了无法访问的第三方库的下载。
注意:goproxy必须在go1.11以上版本,并且开启了go module机制后才能使用的(因为我当前的环境都是1.12,大家可以验证下小版本是否支持)
而在国内,质量比较好的几个goproxy
代理大概有如下几个:
go代理使用
# 开启go module支持
# golang1.11 需要手动开启,golang1.12之后默认会开启
$ export GO111MODULE=on
# 设置代理(上述三个代理地址都可以)
$ export GOPROXY=https://goproxy.cn
# 下载第三方库
$ go get -v golang.org/x/net/websocket
Fetching https://goproxy.cn/golang.org/x/net/websocket/@v/list
Fetching https://goproxy.cn/golang.org/x/net/@v/list
go: finding golang.org/x/net latest
Fetching https://goproxy.cn/golang.org/x/net/@latest
Fetching https://goproxy.cn/golang.org/x/net/@v/v0.0.0-20190827160401-ba9fcec4b297.mod
golang.org/x/net/websocket