在項目開發中,配置文件的合理的獲取和更新是一個基本的功能。項目上線後修改配置項,修改配置以後若是還從新啓動項目才能生效,這樣效果並很差。爲了可以在不影響項目正常運行的狀況下修改配置項,就須要用到配置熱更新。例如:上線後想要修改日誌的級別,能夠直接修改配置文件,項目自動掃描配置文件,若是發現文件被修改,則從新獲取配置信息。讀取配置和配置熱更新有兩種方式:mysql
package main import ( "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 }
package utils import ( "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 { Drive string `yaml:"drive"` Address string `yaml:"address"` } type Token struct { Salt string `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 }
package utils import ( "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 { Drive string `yaml:"drive"` Address string `yaml:"address"` } type Token struct { Salt string `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 }
package main import ( "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()) } }