theme: jzman
「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!」
配置文件在一个项目中至关重要,如何高效的读取配置尤为关键。如果不采用任何三方库,最常用的方式是通过文件I/O获取文件的内容,但我毕竟只是想要读取个配置文件,这还要进行文件操作,未免有些造轮子了。而且,文件的格式多种多样,如何格式的读取文件内容和根据不同的环境读取也是一个不小的挑战。这篇文章我介绍四种读取配置文件的方式,请按照各自的需求选择。
一、四种读取方式简介
比较出众的有两种,包括Viper
和GoDotEnv
,这两种方式受众相当的广泛,Viper
在Github
的star最多,文档更加全面,GoDotEnv
次之。另外还有两个比较小众轻量级的,包括gonfig
和go-akka
。分别的介绍请参考Github介绍。
go-akka
Currently Not Available !!!
godotenv(Available)
A Go (golang) port of the Ruby dotenv project (which loads env vars from a .env file)
gonfig
gonfig is a lightweight Golang package for intergrating both JSON configs and enviornment variables into one config object.
viper(Available,Most stars)
Viper is heading towards v2 and we would love to hear what you would like to see in it.
二、go-akka实践
配置文件config.yaml
port: 8081 debug: true
解析配置config.go
import "github.com/go-akka/configuration" type Config struct { Port uint16 `yaml:"port"` Debug bool `yaml:"debug"` Raw *configuration.Config } func (c *Config) parseConfig(path string) *Config { c.Raw = configuration.LoadConfig(path) c.Port = uint16(c.Raw.GetInt32("port", 8008)) c.Debug = c.Raw.GetBoolean("debug", false) return c }
测试config_test.go
func TestConfig(t *testing.T) { assert.NotPanics(t, func() { cfg := new(Config).parseConfig("./cfg.yaml") fmt.Printf(" port=%d,debug=%t", cfg.Port, cfg.Debug) }) }
三、godotenv实践
测试文件 .env
Key1=value1 Key2 =value2
解析配置config.go
func init() { if err := godotenv.Load("./.env"); err != nil { log.Fatal("Error loading .env file") } } func ReadEnv() { value1 := os.Getenv("Key1") value2 := os.Getenv("Key2") value3 := os.Getenv("Key3") if value1 == "" || value2 == "" { panic("load error") } fmt.Printf("key1=%s,key2=%s,key3=%s", value1, value2, value3) }
测试文件config_test.go
func TestEnv(t *testing.T) { assert.NotPanics(t, func() { ReadEnv() }) }
四、gonfig 实践
配置文件
dev_config.json
{ "DB_USERNAME": "test", "DB_PASSWORD": "test", "DB_PORT": "3306", "DB_HOST": "127.0.0.1", "DB_NAME": "test" }
prd_config.json
{ "DB_USERNAME": "prd_test", "DB_PASSWORD": "prd_test", "DB_PORT": "3306", "DB_HOST": "127.0.0.1", "DB_NAME": "prd_test" }
配置解析config.go
type Configuration struct { DB_USERNAME string DB_PASSWORD string DB_PORT string DB_HOST string DB_NAME string } func ParseConfig(params ...string) Configuration { configuration := Configuration{} env := "dev" if len(params) > 0 { env = params[0] } fName := fmt.Sprintf("./%s_config.json", env) if err := gonfig.GetConf(fName, &configuration); err != nil { panic(err) } return configuration }
测试文件config_test.go
func TestConfig(t *testing.T) { assert.NotPanics(t, func() { fmt.Println("Dev Conf :") cfg := ParseConfig() fmt.Printf("userName=%s,password=%s,port=%s,host=%s,name=%s \n", cfg.DB_USERNAME, cfg.DB_PASSWORD, cfg.DB_PORT, cfg.DB_HOST, cfg.DB_NAME) cfg = ParseConfig("prd") fmt.Printf("userName=%s,password=%s,port=%s,host=%s,name=%s \n", cfg.DB_USERNAME, cfg.DB_PASSWORD, cfg.DB_PORT, cfg.DB_HOST, cfg.DB_NAME) }) }
五、viper实践
配置文件config.yml
server: port: 8080 database: dbname: dbuser: "dbuser" dbpassword: "dbpassword" EXAMPLE_VAR: "variable from config.yml" EXAMPLE_PATH: "path from config.yml"
解析配置config.go
type Configurations struct { Server ServerConfigurations Database DatabaseConfigurations EXAMPLE_PATH string EXAMPLE_VAR string } // ServerConfigurations exported type ServerConfigurations struct { Port int } // DatabaseConfigurations exported type DatabaseConfigurations struct { DBName string DBUser string DBPassword string } func readConfig() { viper.SetConfigName("config") viper.AddConfigPath(".") viper.AutomaticEnv() viper.SetConfigType("yml") var configuration Configurations if err := viper.ReadInConfig(); err != nil { fmt.Printf("Error reading config file, %s", err) } viper.SetDefault("database.dbname", "test_db") err := viper.Unmarshal(&configuration) if err != nil { fmt.Printf("Unable to decode into struct, %v", err) } fmt.Printf("reading using model:\n database=%s,port=%d,path=%s,var=%s \n", configuration.Database.DBName, configuration.Server.Port, configuration.EXAMPLE_PATH, configuration.EXAMPLE_VAR) fmt.Printf("reading without model:\n database=%s,port=%d,path=%s,var=%s \n", viper.GetString("database.dbname"), viper.GetInt("server.port"), viper.GetString("EXAMPLE_PATH"), viper.GetString("EXAMPLE_VAR")) }
测试文件config_test.go
func TestConfig(t *testing.T) { assert.NotPanics(t, func() { readConfig() }) }
六、总结
四种读取环境配置的实践按照各自情况挑选吧,生产环境建议还是使用viper
和godotenv
,毕竟千锤百炼要可靠很多,还有友情提示永远不要忘记在.gitignore
中包含你的环境变量文件。
哥佬倌,莫慌到走!觉好留个赞,探讨上评论。欢迎关注实践go语言专栏gothing,手把手一起学习go。也欢迎关注我,一定做一个长更的好男人。