Golang實(shí)現(xiàn)獲取系統(tǒng)環(huán)境變量的方法詳解
1、Golang 獲取系統(tǒng)環(huán)境變量
Golang 要獲取系統(tǒng)的環(huán)境變量需要導(dǎo)入"os"包,通過os包中的Getenv方法來獲取。
func Getenv(key string) string {
}示例代碼:
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println(os.Getenv("GOPATH"))
} 2、通過godotenv庫配置環(huán)境變量
2.1 簡介
微服務(wù)應(yīng)用提倡將配置存儲(chǔ)在環(huán)境變量中。任何從開發(fā)環(huán)境切換到生產(chǎn)環(huán)境時(shí)需要修改的東西都從代碼抽取到環(huán)境變量里。但是在實(shí)際開發(fā)中,如果同一臺(tái)機(jī)器運(yùn)行多個(gè)項(xiàng)目,設(shè)置環(huán)境變量容易沖突,不實(shí)用。godotenv庫從.env文件中讀取配置, 然后存儲(chǔ)到程序的環(huán)境變量中。在代碼中可以使用讀取非常方便。godotenv源于一個(gè) Ruby 的開源項(xiàng)目dotenv。
2.2 快速使用
第三方庫需要先安裝:
go get github.com/joho/godotenv
后使用:
package main
import (
"fmt"
"log"
"os"
"github.com/joho/godotenv"
)
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal(err)
}
fmt.Println("name: ", os.Getenv("name"))
fmt.Println("age: ", os.Getenv("age"))
}然后在可執(zhí)行程序相同目錄下,添加一個(gè).env文件:
name = zmc
age = 20
運(yùn)行程序,輸出:
name = zmc
age = 20
可見,使用非常方便。默認(rèn)情況下,godotenv讀取項(xiàng)目根目錄下的.env文件,文件中使用key = value的格式,每行一個(gè)鍵值對(duì)。調(diào)用godotenv.Load()即可加載,可直接調(diào)用os.Getenv("key")讀取。
2.3 高級(jí)特性
自動(dòng)加載
如果連Load方法都不想自己調(diào)用,可以導(dǎo)入github.com/joho/godotenv/autoload,配置會(huì)自動(dòng)讀取:
package main
import (
"fmt"
"os"
_ "github.com/joho/godotenv/autoload"
)
func main() {
fmt.Println("name: ", os.Getenv("name"))
fmt.Println("age: ", os.Getenv("age"))
}注意,由于代碼中沒有顯式用到godotenv庫,需要使用空導(dǎo)入,即導(dǎo)入時(shí)包名前添加一個(gè)_。
看autoload包的源碼,其實(shí)就是庫幫你調(diào)用了Load方法:
// src/github.com/joho/godotenv/autoload/autoload.go
package autoload
/*
You can just read the .env file on import just by doing
import _ "github.com/joho/godotenv/autoload"
And bob's your mother's brother
*/
import"github.com/joho/godotenv"
func init() {
godotenv.Load()
}加載自定義文件
默認(rèn)情況下,加載的是項(xiàng)目根目錄下的.env文件。當(dāng)然我們可以加載任意名稱的文件,文件也不必以.env為后綴:
package main
import (
"fmt"
"log"
"os"
"github.com/joho/godotenv"
)
func main() {
err := godotenv.Load("common", "dev.env", "production.env")
if err != nil {
log.Fatal(err)
}
fmt.Println("name: ", os.Getenv("name"))
fmt.Println("version: ", os.Getenv("version"))
fmt.Println("database: ", os.Getenv("database"))
}common文件內(nèi)容:
name = awesome web
version = 0.0.1
dev.env文件內(nèi)容:
database = sqlite
production.env文件內(nèi)容:
database = mysql
運(yùn)行結(jié)果:
name: awesome web
version: 0.0.1
database: sqlite
注意:Load接收多個(gè)文件名作為參數(shù),如果不傳入文件名,默認(rèn)讀取.env文件的內(nèi)容。如果多個(gè)文件中存在同一個(gè)鍵,那么先出現(xiàn)的優(yōu)先,后出現(xiàn)的不生效。所以,上面輸出的database是sqlite。
注釋
.env文件中可以添加注釋,注釋以#開始,直到該行結(jié)束。
# app name name = awesome web # current version version = 0.0.1
YAML
.env文件還可以使用 YAML 格式:
name: awesome web version: 0.0.1
不存入環(huán)境變量(重要)
godotenv允許不將.env文件內(nèi)容存入環(huán)境變量,使用godotenv.Read()返回一個(gè)map[string]string,可直接使用:
package main
import (
"fmt"
"log"
"github.com/joho/godotenv"
)
func main() {
var myEnv map[string]string
myEnv, err := godotenv.Read()
if err != nil {
log.Fatal(err)
}
fmt.Println("name: ", myEnv["name"])
fmt.Println("version: ", myEnv["version"])
}輸出:
name: awesome web
version: 0.0.1
直接操作map,簡單直接!
數(shù)據(jù)源
除了讀取文件,還可以從string、中讀取配置:io.Reader
package main
import (
"fmt"
"log"
"github.com/joho/godotenv"
)
func main() {
content := `
name: awesome web
version: 0.0.1
`
myEnv, err := godotenv.Unmarshal(content)
if err != nil {
log.Fatal(err)
}
fmt.Println("name: ", myEnv["name"])
fmt.Println("version: ", myEnv["version"])
}輸出:
name: awesome web
version: 0.0.1
只要實(shí)現(xiàn)了io.Reader接口,就能作為數(shù)據(jù)源??梢詮奈募?code>os.File),網(wǎng)絡(luò)(net.Conn),bytes.Buffer等多種來源讀?。?/p>
package main
import (
"bytes"
"fmt"
"log"
"os"
"github.com/joho/godotenv"
)
func main() {
file, _ := os.OpenFile(".env", os.O_RDONLY, 0666)
myEnv, err := godotenv.Parse(file)
if err != nil {
log.Fatal(err)
}
fmt.Println("name: ", myEnv["name"])
fmt.Println("version: ", myEnv["version"])
buf := &bytes.Buffer{}
buf.WriteString("name: awesome web @buffer")
buf.Write([]byte{'\n'})
buf.WriteString("version: 0.0.1")
myEnv, err = godotenv.Parse(buf)
if err != nil {
log.Fatal(err)
}
fmt.Println("name: ", myEnv["name"])
fmt.Println("version: ", myEnv["version"])
}輸出:
version: 0.0.1
name: awesome web @buffer
version: 0.0.1
注意,從字符串讀取和從io.Reader讀取使用的方法是不同的。前者為Unmarshal,后者是Parse。
生成.env文件
可以通過程序生成一個(gè).env文件的內(nèi)容,可以直接寫入到文件中:
package main
import (
"bytes"
"log"
"github.com/joho/godotenv"
)
func main() {
buf := &bytes.Buffer{}
buf.WriteString("name = awesome web")
buf.WriteByte('\n')
buf.WriteString("version = 0.0.1")
env, err := godotenv.Parse(buf)
if err != nil {
log.Fatal(err)
}
err = godotenv.Write(env, "./.env")
if err != nil {
log.Fatal(err)
}
}查看生成的.env文件:
name="awesome web"
version="0.0.1"
還可以返回一個(gè)字符串:
package main
import (
"bytes"
"fmt"
"log"
"github.com/joho/godotenv"
)
func main() {
buf := &bytes.Buffer{}
buf.WriteString("name = awesome web")
buf.WriteByte('\n')
buf.WriteString("version = 0.0.1")
env, err := godotenv.Parse(buf)
if err != nil {
log.Fatal(err)
}
content, err := godotenv.Marshal(env)
if err != nil {
log.Fatal(err)
}
fmt.Prin輸出:
ame="awesome web"
version="0.0.1"
命令行模式
godotenv還提供了一個(gè)命令行的模式:
godotenv -f ./.env command args
前面在go get安裝godotenv時(shí),godotenv就已經(jīng)安裝在$GOPATH/bin目錄下了,我習(xí)慣把$GOPATH/bin加入系統(tǒng)PATH,所以godotenv命令可以直接使用。
命令行模式就是讀取指定文件(如果不通過-f指定,則使用.env文件),設(shè)置環(huán)境變量,然后運(yùn)行后面的程序。
我們簡單寫一個(gè)程序驗(yàn)證一下:
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println(os.Getenv("name"))
fmt.Println(os.Getenv("version"))
}使用godotenv運(yùn)行一下:
godotenv -f ./.env go run main.go
輸出:
awesome web
0.0.1
多個(gè)環(huán)境
實(shí)踐中,一般會(huì)根據(jù)APP_ENV環(huán)境變量的值加載不同的文件:
package main
import (
"fmt"
"log"
"os"
"github.com/joho/godotenv"
)
func main() {
env := os.Getenv("GODAILYLIB_ENV")
if env == "" {
env = "development"
}
err := godotenv.Load(".env." + env)
if err != nil {
log.Fatal(err)
}
err = godotenv.Load()
if err != nil {
log.Fatal(err)
}
fmt.Println("name: ", os.Getenv("name"))
fmt.Println("version: ", os.Getenv("version"))
fmt.Println("database: ", os.Getenv("database"))
}我們先讀取環(huán)境變量GODAILYLIB_ENV,然后讀取對(duì)應(yīng)的.env. + env,最后讀取默認(rèn)的.env文件。
前面也提到過,先讀取到的優(yōu)先。我們可以在默認(rèn)的.env文件中配置基礎(chǔ)信息和一些默認(rèn)的值, 如果在開發(fā)/測試/生產(chǎn)環(huán)境需要修改,那么在對(duì)應(yīng)的.env.development/.env.test/.env.production文件中再配置一次即可。
.env文件內(nèi)容:
name = awesome web version = 0.0.1 database = file
.env.development文件內(nèi)容:
database = sqlite3
.env.production文件內(nèi)容:
database = mysql
運(yùn)行程序:
# 默認(rèn)是開發(fā)環(huán)境 $ go run main.go name: awesome web version: 0.0.1 database: sqlite3 # 設(shè)置為生產(chǎn)環(huán)境 $ GODAILYLIB_ENV=production go run main.go name: awesome web version: 0.0.1 database: mysql
2.4 一點(diǎn)源碼
godotenv讀取文件內(nèi)容,為什么可以使用os.Getenv訪問:
// src/github.com/joho/godotenv/godotenv.go
func loadFile(filename string, overload bool) error {
envMap, err := readFile(filename)
if err != nil {
return err
}
currentEnv := map[string]bool{}
rawEnv := os.Environ()
for _, rawEnvLine := range rawEnv {
key := strings.Split(rawEnvLine, "=")[0]
currentEnv[key] = true
}
for key, value := range envMap {
if !currentEnv[key] || overload {
os.Setenv(key, value)
}
}
returnnil
}因?yàn)?code>godotenv調(diào)用os.Setenv將鍵值對(duì)設(shè)置到環(huán)境變量中了。
到此這篇關(guān)于Golang實(shí)現(xiàn)獲取系統(tǒng)環(huán)境變量的方法詳解的文章就介紹到這了,更多相關(guān)Golang獲取系統(tǒng)環(huán)境變量內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go利用反射reflect實(shí)現(xiàn)獲取接口變量信息
反射是通過實(shí)體對(duì)象獲取反射對(duì)象(Value、Type),然后可以操作相應(yīng)的方法。本文將利用Go語言中的反射reflect實(shí)現(xiàn)獲取接口變量信息,需要的可以參考一下2022-05-05
golang切片擴(kuò)容規(guī)則實(shí)現(xiàn)
這篇文章主要介紹了golang切片擴(kuò)容規(guī)則實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Golang的Fork/Join實(shí)現(xiàn)代碼
Fork/Join本質(zhì)上是一種任務(wù)分解,將一個(gè)很大的任務(wù)分解成若干個(gè)小任務(wù),然后再對(duì)小任務(wù)進(jìn)一步分解,直到最小顆粒度,然后并發(fā)執(zhí)行,對(duì)Golang的Fork/Join實(shí)現(xiàn)代碼感興趣的朋友跟隨小編一起看看吧2023-01-01

