文章目录

  • 思路
  • 实现
  • 编写配置文件
  • 编写结构体
  • 读取文件
  • 使用


作者:lomtom



你的支持就是我最大的动力。

熟悉使用SpringBoot的同学,再去使用Go之后,就会发现SpringBoot的配置文件是真的很方便

而在Go,他却不支持这样的做法,那么,我们只能自己实现类似于SpringBoot配置文件的做法了。

思路

配置文件有很多种,例如json、xml、yml、toml 或者是键值对的形式。

虽然说配置文件各种各样,但是总体处理步骤都大致相同

  1. 编写配置文件
  2. 编写与配置文件相对应的结构体
  3. 读取配置文件并且加载到相对应的结构体当中

实现

由于使用SpringBoot,感受到yml文件的方便、简洁,所以这里以yml文件为例

编写配置文件

新建配置文件,命名随意,后缀保证为yml即可。

server:
  port: 8000
  runMode: debug # release debug
  logLevel: debug # debug info warn error

database:
  type: mysql
  host: localhost
  port: 32306
  username: root
  password: 123456
  dbname: test
  max_idle_conn: 10
  max_open_conn: 30
  conn_max_lifetime: 300

redis:
  host: localhost
  port: 32307
  password:
  db: 0

在这里也是类似于SpringBoot的常用配置,设置了mysql、redis的相关设置

编写结构体

结构体需要与yml的层级关系相对应,并且加入yaml:"server"方便系统识别

var Server *server
var Database *database
var Redis *myRedis

type conf struct {
	Svc         server   `yaml:"server"`
	DB          database `yaml:"database"`
	RedisConfig myRedis  `yaml:"redis"`
}

type server struct {
	Port     int    `yaml:"port"`
	RunMode  string `yaml:"runMode"`
	LogLevel string `yaml:"logLevel"`
}

type database struct {
	Type            string `yaml:"type"`
	Host            string `yaml:"host"`
	Port            string `yaml:"port"`
	UserName        string `yaml:"username"`
	Password        string `yaml:"password"`
	DbName          string `yaml:"dbname"`
	MaxIdleConn     int    `yaml:"max_idle_conn"`
	MaxOpenConn     int    `yaml:"max_open_conn"`
	ConnMaxLifetime int    `yaml:"conn_max_lifetime"`
}

type myRedis struct {
	Host     string `yaml:"host"`
	Port     string `yaml:"port"`
	Password string `yaml:"password"`
	DB       int    `yaml:"db"`
}

当然,除此之外,也可以重写他们的String方法,方便项目启动时,能够有序的打印,同样也可以更方便直观的看出配置文件有没有加载成功

func (c conf) String() string {
	return fmt.Sprintf("%v\n%v\n%v", c.Svc, c.DB, c.RedisConfig)
}

func (s server) String() string {
	return fmt.Sprintf("server : \n"+
		"\tport : %v \n"+
		"\tRunMode : %v", s.Port, s.RunMode)
}

func (m database) String() string {
	return fmt.Sprintf("database : \n"+
		"\ttype : %v \n"+
		"\thost : %v \n"+
		"\tport : %v \n"+
		"\tusername : %v \n"+
		"\tpassword : %v \n"+
		"\tdbname : %v \n"+
		"\tmax_idle_conn : %v \n"+
		"\tmax_open_conn : %v \n"+
		"\tconn_max_lifetime : %v",
		m.Type, m.Host, m.Port, m.UserName, m.Password, m.DbName, m.MaxOpenConn, m.MaxIdleConn, m.ConnMaxLifetime)
}
func (r myRedis) String() string {
	return fmt.Sprintf("redis : \n"+
		"\thost : %v \n"+
		"\tport : %v \n"+
		"\tPassword : %v \n"+
		"\tdb : %v",
		r.Host, r.Port, r.Password, r.DB)
}

读取文件

重头戏来咯!!!

前提:引入依赖

go get gopkg.in/yaml.v2

需要做的就是将配置文件中的信息读取出来,并且绑定到相应的结构体当中。

func InitConf(dataFile string) {
	// 解决相对路经下获取不了配置文件问题
	_, filename, _, _ := runtime.Caller(0)
	filePath := path.Join(path.Dir(filename), dataFile)
	_, err := os.Stat(filePath)
	if err != nil {
		log.Printf("config file path %s not exist", filePath)
	}
	yamlFile, err := ioutil.ReadFile(filePath)
	if err != nil {
		log.Printf("yamlFile.Get err   #%v ", err)
	}
	c := new(conf)
	err = yaml.Unmarshal(yamlFile, &c)
	if err != nil {
		log.Printf("Unmarshal: %v", err)
	}
	log.Printf("load conf success\n %v", c)
	// 绑定到外部可以访问的变量中
	Server = &c.Svc
	Database = &c.DB
	Redis = &c.RedisConfig
}

如果使用相对路经读取不到文件的,可以加入一下代码

_, filename, _, _ := runtime.Caller(0)
	filePath := path.Join(path.Dir(filename), dataFile)

使用

加载配置文件,可以在init方法(项目启动自动执行,无需调用)中加载

func init() {
	// 加载配置文件
	config.InitConf("../../config/app-dev.yaml")
}

注意路径是读取配置文件工具相对于配置文件的路径,而不是init方法相对配置文件的路径
例如我的是

├─config
│   └─ app-dev.yaml
└─util
│   └─config
│       └─ ConfigUtil.go
└─main.go

使用的时候直接调用结构体即可

例如,需要指定gin模式,对应的是Server.RunMode,其他同理

func InitRouters() *gin.Engine {
	r := gin.Default()
	gin.SetMode(config.Server.RunMode)
	return r
}