一文带你读懂微服务Micro框架如何读取配置文件

本文已被阅读过 Posted by 陌无崖 on 2019-08-15

导语

我们在写程序的时候,一个无法避免的步骤就是配置文件的编写,有了配置文件,就要有相应的加载机制,比如读取配置文件到实体中,配置文件因为语法简单,具有灵活性,在程序中被广泛的使用,如今流行的有xml,json,yml等类型的配置文件,这一篇我们主要了解在Micro框架中是如何加载我们的配置文件。

导包

1
2
"github.com/micro/go-micro/config"
"github.com/micro/go-micro/config/source/file"

两个函数

第一个:func file.NewSource(opts ...source.Option) source.Source
使用这个函数可以实现我们对配置文件的加载,具体如何使用呢?让我们来看一个实例:
首先编写一个配置文件config.json

1
2
3
4
5
6
7
8
9
{
"hosts": {
"database": {
"name": "JSON",
"address": "10.0.0.1",
"port": 3306
}
}
}

编写一个main.go,可以看到source.Option参数由file.WithPath()读取了配置文件进行了返回。

1
2
3
4
5
6
7
8
9
func main(){
// 加载配置文件
if err := config.Load(file.NewSource(
file.WithPath("./config/config.json"),
)); err != nil {
fmt.Println(err)
return
}
}

第二个func Get(path ...string) reader.Value
我们将要使用这个函数对配置文件的值读取出来。同样使用上面的配置文件。我们进行读取,从下面的函数中可以看出来,首先需要定义一个实体,然后对配置文件读出赋值操作。

1
2
3
4
5
6
7
8
9
10
11
// 定义我们的额数据结构
type Host struct {
Name string `json:"name"`
Address string `json:"address"`
Port int `json:"port"`
}
var host Host
if err := config.Get("hosts", "database").Scan(&host); err != nil {
fmt.Println(err)
return
}

现在我们测试一下,main.go源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func main() {
// 加载配置文件
if err := config.Load(file.NewSource(
file.WithPath("./config/config.json"),
// file.WithPath("./config/config.yml"),
)); err != nil {
fmt.Println(err)
return
}

// 定义我们的额数据结构
type Host struct {
Name string `json:"name"`
Address string `json:"address"`
Port int `json:"port"`
}
var host Host

if err := config.Get("hosts", "database").Scan(&host); err != nil {
fmt.Println(err)
return
}
fmt.Println(host.Name, host.Address, host.Port)
}

输出结果,可以看出我们轻松读取了我们的配置文件。

1
2
PS F:\micolearn\day03\micro-config> go run .\main.go
JSON 10.0.0.1 3306

疑问一?

在上面的json文件中明明是一个结构体中包含了另一个结构体,name、address、port的值应该在Database结构体中,为什么读取的时候,放在了Host结构体中?

func Get(path ...string) reader.Value的参数中,我们可以注意到这是一个可变参数,我们可以传入无限个字符串,使用一个结构体,是Micro的取巧方式,上述代码代表取出hosts层级下的database的属性,只要在Host中可以做转换即可以转换。当然我们也可以用下面的方式做。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type HostAddress struct {
Database `json:"database"`
}
type Database struct {
Name string `json:"name"`
Address string `json:"address"`
Port int `json:"port"`
}
var hostthree HostAddress
if err := config.Get("hostthree").Scan(&hostthree); err != nil {
fmt.Println(err)
return
}
fmt.Println(hostthree.Database)

最后的打印结果是一个结构体

1
{JSON 10.0.0.1 3306}

疑问二?

我们可不可以不用嵌套这个结构体呢?

当然可以,这时候我们只需要在参数中传一个参数就行了,如下

1
2
3
4
5
6
7
{
"hosttwo": {
"name": "JSON",
"address": "10.0.0.1",
"port": 3306
}
}

读取,我们同样直接使用Host结构体

1
2
3
4
5
6
7
var hosttwo Host

if err := config.Get("hosttwo").Scan(&hosttwo); err != nil {
fmt.Println(err)
return
}
fmt.Println(hosttwo.Name, hosttwo.Address, hosttwo.Port)

打印测试后的结果

1
JSON 10.0.0.1 3306

疑问三?

以上都是比较简单的结构体,如果换成比较复杂的结构体,比如嵌套一个数组,也可以吗?

当然可以,其实在赋值的时候,我们不需要管结构体的内容,如果可以匹配到相应的值,就可以直接赋值。现在我们编写一个json文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"hostfour": [
{
"name": "JSON",
"address": "10.0.0.1",
"port": 3306
},
{
"name": "JSON",
"address": "10.0.0.1",
"port": 3306
},
{
"name": "JSON",
"address": "10.0.0.1",
"port": 3306
}
]
}

同样编写我们的main.go,我们同样使用之前的Host结构体,从下面的函数体可以看出,我们仅仅改变了定义变量,定义成数组的类型进行存储。其它的根本不需要任何改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type Host struct {
Name string `json:"name"`
Address string `json:"address"`
Port int `json:"port"`
}
func main(){
// 加载配置文件
if err := config.Load(file.NewSource(
file.WithPath("./config/config.json"),
// file.WithPath("./config/config.yml"),
)); err != nil {
fmt.Println(err)
return
}
var hostfour []Host
if err := config.Get("hostfour").Scan(&hostfour); err != nil {
fmt.Println(err)
return
}
fmt.Println(hostfour)
}

测试结果,可以看出成功打印了我们的值

1
[{JSON 10.0.0.1 3306} {JSON 10.0.0.1 3306} {JSON 10.0.0.1 3306}]

> 非常感谢你保持着耐心读完这篇文章,我是陌无崖,一个专注于Golang后端开发的互联网从业人员,熟悉RabbitMQ,Docker,微服务等,获取更多知识分享,文章末尾扫码关注,每日推送,准时获取更多分享。 >

推荐阅读


本文欢迎转载,转载请联系作者,谢谢!


打开微信扫一扫,关注微信公众号