gcfg
组件采用接口化设计,默认提供的是基于文件系统的接口实现。支持的数据文件格式包括: JSON/XML/YAML(YML)/TOML/INI/PROPERTIES
,项目中开发者可以灵活地选择自己熟悉的配置文件格式来进行配置管理。
配置文件
默认配置文件
配置对象我们推荐使用单例方式获取,单例对象将会按照文件后缀toml/yaml/yml/json/ini/xml/properties
文自动检索配置文件。默认情况下会自动检索配置文件config.toml/yaml/yml/json/ini/xml/properties
并缓存,配置文件在外部被修改时将会自动刷新缓存。
如果想要自定义文件格式,可以通过SetFileName
方法修改默认读取的配置文件名称(如:default.yaml
, default.json
, default.xml
等等)。例如,我们可以通过以下方式读取default.yaml
配置文件中的数据库database
配置项。
// 设置默认配置文件,默认读取的配置文件设置为 default.yaml
g.Cfg().GetAdapter().(*gcfg.AdapterFile).SetFileName("default.yaml")
// 后续读取时将会读取到 default.yaml 配置文件内容
g.Cfg().Get(ctx, "database")
默认文件修改
文件可以是一个具体的文件名称或者完整的文件绝对路径。
我们可以通过多种方式修改默认文件名称:
- 通过配置管理方法
SetFileName
修改。 - 修改命令行启动参数 -
gf.gcfg.file
。 - 修改指定的环境变量 -
GF_GCFG_FILE
。
假如我们的执行程序文件为main
,那么可以通过以下方式修改配置管理器的配置文件目录(Linux
下):
通过单例模式
g.Cfg().GetAdapter().(*gcfg.AdapterFile).SetFileName("default.yaml")
通过命令行启动参数
./main --gf.gcfg.file=config.prod.toml
通过环境变量(常用在容器中)
启动时修改环境变量:
GF_GCFG_FILE=config.prod.toml; ./main
使用
genv
模块来修改环境变量:genv.Set("GF_GCFG_FILE", "config.prod.toml")
配置目录
目录配置方法
gcfg
配置管理器支持非常灵活的多目录自动搜索功能,通过SetPath
可以修改目录管理目录为唯一的目录地址,同时,我们推荐通过AddPath
方法添加多个搜索目录,配置管理器底层将会按照添加目录的顺序作为优先级进行自动检索。直到检索到一个匹配的文件路径为止,如果在所有搜索目录下查找不到配置文件,那么会返回失败。
默认目录配置
gcfg
配置管理对象初始化时,默认会自动添加以下配置文件搜索目录:
- 当前工作目录及其下的
config
、manifest/config
目录:例如当前的工作目录为/home/www
时,将会添加:/home/www
/home/www/config
/home/www/manifest/config
- 当前可执行文件所在目录及其下的
config
、manifest/config
目录:例如二进制文件所在目录为/tmp
时,将会添加:/tmp
/tmp/config
/tmp/manifest/config
- 当前
main
源代码包所在目录及其下的config
、manifest/config
目录(仅对源码开发环境有效):例如main
包所在目录为/home/john/workspace/gf-app
时,将会添加:/home/john/workspace/gf-app
/home/john/workspace/gf-app/config
/home/john/workspace/gf-app/manifest/config
默认目录修改
注意这里修改的参数必须是一个目录,不能是文件路径。
我们可以通过以下方式修改配置管理器的配置文件搜索目录,配置管理对象将会只在该指定目录执行配置文件检索:
- 通过配置管理器的
SetPath
方法手动修改; - 修改命令行启动参数 -
gf.gcfg.path
; - 修改指定的环境变量 -
GF_GCFG_PATH
;
假如我们的执行程序文件为main
,那么可以通过以下方式修改配置管理器的配置文件目录(Linux下):
通过单例模式
g.Cfg().GetAdapter().(*gcfg.AdapterFile).SetPath("/opt/config")
通过命令行启动参数
./main --gf.gcfg.path=/opt/config/
通过环境变量(常用在容器中)
启动时修改环境变量:
GF_GCFG_PATH=/opt/config/; ./main
使用
genv
模块来修改环境变量:genv.Set("GF_GCFG_PATH", "/opt/config")
内容配置
gcfg
包也支持直接内容配置,而不是读取配置文件,常用于程序内部动态修改配置内容。通过以下包配置方法实现全局的配置:
func (c *AdapterFile) SetContent(content string, file ...string)
func (c *AdapterFile) GetContent(file ...string) string
func (c *AdapterFile) RemoveContent(file ...string)
func (c *AdapterFile) ClearContent()
需要注意的是该配置是全局生效的,并且优先级会高于读取配置文件。因此,假如我们通过SetContent("v = 1", "config.toml")
配置了config.toml
的配置内容,并且也同时存在config.toml
配置文件,那么只会使用到SetContent
的配置内容,而配置文件内容将会被忽略。
层级访问
在默认提供的文件系统接口实现下,gcfg
组件支持按层级获取配置数据,层级访问默认通过英文.
号指定,其中pattern
参数和 通用编解码-gjson 的pattern
参数一致。例如以下配置(config.yaml
):
server:
address: ":8199"
serverRoot: "resource/public"
database:
default:
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/focus"
debug: true
例如针对以上配置文件内容的层级读取:
// :8199
g.Cfg().Get(ctx, "server.address")
// true
g.Cfg().Get(ctx, "database.default.debug")
注意事项
大家都知道,在Golang
里面,map/slice
类型其实是一个”引用类型”(也叫”指针类型”),因此当你对这种类型的变量 键值对/索引项 进行修改时,会同时修改到其对应的底层数据。从效率上考虑,gcfg
包某些获取方法返回的数据类型为map/slice
时,没有对其做值拷贝,因此当你对返回的数据进行修改时,会同时修改gcfg
对应的底层数据。
例如:
配置文件:
// config.json:
`{"map":{"key":"value"}, "slice":[59,90]}`
示例代码:
var ctx = gctx.New()
m := g.Cfg().MustGet(ctx, "map").Map()
fmt.Println(m)
// Change the key-value pair.
m["key"] = "john"
// It changes the underlying key-value pair.
fmt.Println(g.Cfg().MustGet(ctx, "map").Map())
s := g.Cfg().MustGet(ctx, "slice").Slice()
fmt.Println(s)
// Change the value of specified index.
s[0] = 100
// It changes the underlying slice.
fmt.Println(g.Cfg().MustGet(ctx, "slice").Slice())
// output:
// map[key:value]
// map[key:john]
// [59 90]
// [100 90]
检测更新
配置管理器使用了缓存机制,当配置文件第一次被读取后会被缓存到内存中,下一次读取时将会直接从缓存中获取,以提高性能。同时,配置管理器提供了对配置文件的自动检测更新机制,当配置文件在外部被修改后,配置管理器能够即时地刷新配置文件的缓存内容。