项目配置文件获取及更新热更新
【项目配置文件获取及更新热更新】在项目开发中,配置文件的合理的获取和更新是一个基本的功能。项目上线后修改配置项,修改配置之后如果还重新启动项目才能生效,这样效果并不好。为了能够在不影响项目正常运行的情况下修改配置项,就需要用到配置热更新。例如:上线后想要修改日志的级别,可以直接修改配置文件,项目自动扫描配置文件,如果发现文件被修改,则重新获取配置信息。读取配置和配置热更新有两种方式:
- 方式一:调用github.com/fsnotify/fsnotify包,监控配置变化,并使用其他的包来读取文件
- 方式二:调用github.com/spf13/viper包,这个包是由Steve Francia开发,提供了监控和配置的设置、获取的方法
- main.go文件
package mainimport (
"file-store/handler"
"file-store/models"
"file-store/utils"
"fmt"
"log"
"net/http""github.com/fsnotify/fsnotify"
)func main() {
configPath := "/Users/apple/workplace/file-store/config/config.yaml"
configDir := "/Users/apple/workplace/file-store/config"// 加载配置文件
_ = utils.InitConfig(configPath, "config")
fmt.Printf("配置为:%s\n", utils.Conf.Token.Salt)watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()done := make(chan bool)
go func() {
for {
select {
case event := <-watcher.Events:
if event.Op&fsnotify.Write == fsnotify.Write {
_ = utils.InitConfig(configPath, "config")
fmt.Printf("更新配置为:%s\n", utils.Conf.Token.Salt)
}
case err := <-watcher.Errors:
log.Println("error:", err)
}
}
}()
fmt.Printf("数据库配置为:%s, %s\n", utils.Conf.Mysql.Drive, utils.Conf.Mysql.Address)
// 数据库操作
models.MysqlInit(utils.Conf.Mysql.Drive, utils.Conf.Mysql.Address)
// 监听端口
err = http.ListenAndServe("127.0.0.1:8000", nil)
if err != nil {
fmt.Printf("Failed to start server, err %s", err.Error())
}// 监控文件
err = watcher.Add(configPath)
if err != nil {
log.Fatal(err)
}
// 监控文件夹
err = watcher.Add(configDir)
if err != nil {
log.Fatal(err)
}
<-done
}
- config.go:该文件用于获取配置信息,读取配置用到两个包:ioutil读取配置,gopkg.in/yaml.v2用于数据的转换
package utilsimport (
"fmt"
"io/ioutil"
"sync""gopkg.in/yaml.v2"
)type Config struct {
File*File`yaml:"file"`
Mysql *Mysql `yaml:"mysql"`
Token *Token `yaml:"token"`
}type File struct {
Path string `yaml:"path"`
}type Mysql struct {
Drivestring `yaml:"drive"`
Address string `yaml:"address"`
}type Token struct {
Saltstring `yaml:"salt"`
Issue string `yaml:"issue"`
}var Conf *Config// InitConfig 读取yaml配置文件
func InitConfig(configPath, configName string) error {
var locker = new(sync.RWMutex)
yamlFile, err := ioutil.ReadFile(configPath)
if err != nil {
panic(err)
}
locker.Lock()
err1 := yaml.Unmarshal(yamlFile, &Conf)
if err1 != nil {
panic(err)
}
locker.Unlock()
fmt.Println(Conf.Token.Salt)
return nil
}
二、方式二的使用
- config.go文件
package utilsimport (
"fmt""github.com/spf13/viper"
)type Config struct {
File*File`yaml:"file"`
Mysql *Mysql `yaml:"mysql"`
Token *Token `yaml:"token"`
}type File struct {
Path string `yaml:"path"`
}type Mysql struct {
Drivestring `yaml:"drive"`
Address string `yaml:"address"`
}type Token struct {
Saltstring `yaml:"salt"`
Issue string `yaml:"issue"`
}// 全局配置
var config = new(Config)// InitConfig 读取yaml配置文件
func InitConfig(configPath, configName, configType string) error {
viper.SetConfigName(configName) // 配置文件名
viper.SetConfigType(configType) // 配置文件类型,例如:toml、yaml等
viper.AddConfigPath(configPath) // 查找配置文件所在的路径,多次调用可以添加多个配置文件搜索的目录
// 读取配置文件配置,并处理错误
if err := viper.ReadInConfig();
err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError);
ok {
return err
}
}
// 监控配置文件变化
viper.WatchConfig()
viper.Unmarshal(config)
if err := validateConfig(config);
err != nil {
return err
}
return nil
}// 获取全局配置
func GetConfig() *Config {
return config
}// validateConfig:校验配置信息
func validateConfig(conf *Config) error {
var (
file= conf.File.Path
drive= conf.Mysql.Drive
address = conf.Mysql.Address
salt= conf.Token.Salt
issue= conf.Token.Issue
)
if file == "" {
return fmt.Errorf("invalid file path: %s\n", file)
}
if drive == "" {
return fmt.Errorf("invalid drive: %s\n", drive)
}
if address == "" {
return fmt.Errorf("invalid address: %s\n", address)
}
if salt == "" {
return fmt.Errorf("invalid salt: %s\n", salt)
}
if issue == "" {
return fmt.Errorf("invalid issue: %s\n", issue)
}
return nil
}
- main.go文件
package mainimport (
"file-store/handler"
"file-store/models"
"file-store/utils"
"fmt"
"net/http"
)func main() {
configPath := "/Users/apple/workplace/file-store/config"
// 配置初始化
err := utils.InitConfig(configPath, "config", "yaml")
if err != nil {
fmt.Printf("Failed to init config, err is %s\n", err)
}
// 获取全局配置
conf := utils.GetConfig()
fmt.Println(conf.File.Path)
// 数据库操作
models.MysqlInit(conf.Mysql.Drive, conf.Mysql.Address)
// 监听端口
err = http.ListenAndServe("127.0.0.1:8000", nil)
if err != nil {
fmt.Printf("Failed to start server, err %s", err.Error())
}
}
推荐阅读
- 17|17 关山松 第二课作业#公众号项目# D20
- RxJava|RxJava 在Android项目中的使用(一)
- EditText默认不获取焦点弹出键盘
- Hacking|Hacking with iOS: SwiftUI Edition - SnowSeeker 项目(一)
- 靠QQ月入上万灰色暴利偏门的项目
- whlie循环和for循环的应用
- spring|spring boot项目启动websocket
- vuex|vuex 基础结构
- 区块链开发平台(以太坊)
- 如何在手机上查看测试vue-cli构建的项目