Go 博客
App Engine SDK 和工作区 (GOPATH)
引言
发布 Go 1 时,我们引入了 go tool,并随之引入了工作区的概念。工作区(由 GOPATH 环境变量指定)是一种组织代码的约定,可以简化 Go 软件包的获取、构建和安装。如果您不熟悉工作区,请在继续阅读之前先阅读本文或观看此屏幕录像。
直到最近,App Engine SDK 中的工具还不知道工作区。没有工作区,“go get” 命令无法运行,因此应用程序开发者不得不手动安装和更新其应用程序依赖项。这很痛苦。
App Engine SDK 1.7.4 版本完全改变了这一切。dev_appserver 和 appcfg 工具现在都支持工作区。当在本地运行或上传应用程序时,这些工具现在会在 GOPATH 环境变量指定的工作区中搜索依赖项。这意味着您现在可以在构建 App Engine 应用程序时使用“go get”,并且可以在普通 Go 程序和 App Engine 应用程序之间切换,而无需更改您的环境或习惯。
例如,假设您想构建一个使用 OAuth 2.0 与远程服务进行身份验证的应用程序。一个流行的 Go OAuth 2.0 库是 oauth2 软件包,您可以使用此命令将其安装到您的工作区:
go get golang.org/x/oauth2
在编写 App Engine 应用程序时,像在普通 Go 程序中一样导入 oauth 软件包:
import "golang.org/x/oauth2"
现在,无论您是使用 dev_appserver 运行您的应用程序还是使用 appcfg 部署它,工具都会在您的工作区中找到 oauth 软件包。就是这么简单。
混合型独立/App Engine 应用程序
Go App Engine SDK 构建在 Go 的标准 net/http 软件包之上来处理 Web 请求,因此,许多 Go Web 服务器只需稍作修改即可在 App Engine 上运行。例如,godoc 作为独立程序包含在 Go 发布版中,但它也可以作为 App Engine 应用程序运行(godoc 从 App Engine 提供 golang.org 服务)。
但是,如果您可以编写一个既是独立 Web 服务器又是 App Engine 应用程序的程序,那岂不是更好?通过使用 构建约束,您可以做到这一点。
构建约束是行注释,用于确定是否应将文件包含在软件包中。它们最常用于处理各种操作系统或处理器架构的代码。例如,path/filepath 软件包包含文件 symlink.go,该文件指定了一个构建约束,以确保它不会在 Windows 系统(没有符号链接)上构建:
// +build !windows
App Engine SDK 引入了一个新的构建约束项:“appengine”。指定以下内容的文件:
// +build appengine
将由 App Engine SDK 构建,并被 go tool 忽略。相反,指定以下内容的文件:
// +build !appengine
将被 App Engine SDK 忽略,而 go tool 会很乐意构建它们。
goprotobuf 库使用此机制为其编码/解码机制的关键部分提供了两种实现:pointer_unsafe.go 是速度更快的版本,不能在 App Engine 上使用,因为它使用了 unsafe 软件包,而 pointer_reflect.go 是速度较慢的版本,通过使用 reflect 软件包来避免使用 unsafe。
让我们以一个简单的 Go Web 服务器为例,将其转换为混合型应用程序。这是 main.go:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe("localhost:8080", nil)
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello!")
}
使用 go tool 构建它,您将获得一个独立的 Web 服务器可执行文件。
App Engine 基础架构提供了自己的 main 函数,用于运行其等效于 ListenAndServe 的功能。要将 main.go 转换为 App Engine 应用程序,请删除对 ListenAndServe 的调用,并在 init 函数(在 main 之前运行)中注册处理程序。这是 app.go:
package main
import (
"fmt"
"net/http"
)
func init() {
http.HandleFunc("/", handler)
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello!")
}
为了使其成为混合型应用程序,我们需要将其分成一个 App Engine 特定部分、一个独立二进制文件特定部分,以及两个版本共有的部分。在这种情况下,没有 App Engine 特定部分,因此我们只将其分成两个文件:
app.go 指定并注册处理程序函数。它与上面的代码清单完全相同,并且不需要构建约束,因为它应包含在程序的所有版本中。
main.go 运行 Web 服务器。它包含“!appengine”构建约束,因为它只应在构建独立二进制文件时包含。
// +build !appengine
package main
import "net/http"
func main() {
http.ListenAndServe("localhost:8080", nil)
}
要查看更复杂的混合型应用程序,请查看 present tool。
结论
我们希望这些更改能让您更容易地开发具有外部依赖项的应用程序,以及维护包含独立程序和 App Engine 应用程序的代码库。
下一篇文章:并发不是并行
上一篇文章:近期两场 Go 讲座
博客目录