Go語(yǔ)言實(shí)現(xiàn)配置熱加載的方法分享
概述
web項(xiàng)目,經(jīng)常需要熱啟動(dòng)各種各樣的配置信息,一旦這些服務(wù)發(fā)生變更,我們需要重新啟動(dòng)web server,以使配置生效,實(shí)現(xiàn)配置熱加載。這里有幾種方法實(shí)現(xiàn)這個(gè)需求。
go 定時(shí)器協(xié)程實(shí)現(xiàn)
項(xiàng)目結(jié)構(gòu)
首先來(lái)看一下整個(gè)項(xiàng)目的目錄結(jié)構(gòu):
- dyconfig // 項(xiàng)目地址
- config // 配置文件目錄
- api.yaml // 采用yaml格式文件
- global // 代碼文件夾
- config
- config_define
- init
- reload
- go.mod // go package管理依賴的包文件
- go.sum // go package管理打包產(chǎn)生的文件
- main.go // web server的入口,主函數(shù)
代碼細(xì)節(jié)
接下來(lái)依次看一下各文件的主體內(nèi)容:
conf/api.yaml文件定義了配置項(xiàng),包含server的host及port信息。
service: server: env: dev host: 127.0.0.1 port: 9902
global/init.go
package global import ( "context" "path" ) type Config struct { Conf struct { FilePath string LastModifyTime int64 } ctx context.Context cancel context.CancelFunc } func NewConfig() (*Config, error) { conf := new(Config) conf.ctx, conf.cancel = context.WithCancel(context.Background()) conf.Conf.FilePath = path.Join("./config", "api.yaml") APIconfig = conf.loadRoute() go conf.reload() //開(kāi)啟協(xié)程監(jiān)聽(tīng)routeNotify go func() { for { select { case lastModifyTime, ok := <-routeNotify: if !ok { return } conf.Conf.LastModifyTime = lastModifyTime route := routeAtomic.Load().(*APIConf) if route != nil { APIconfig = route } } } }() return conf, nil } func (c *Config) Stop() { c.cancel() }
定義Config 根據(jù)LastModifyTime 判斷是否有發(fā)生變化,F(xiàn)ilePath為文件路徑
go conf.reload()
開(kāi)啟協(xié)程監(jiān)聽(tīng)routeNotify,routeNotify內(nèi)容是文件修改時(shí)間的timestamp
global/reload.go
package global import ( "fmt" "gopkg.in/yaml.v3" "io/ioutil" "os" "sync/atomic" "time" ) const ( CheckInterval = 5 * time.Second ) var ( routeAtomic atomic.Value //原子性,解決并發(fā)問(wèn)題 routeNotify = make(chan int64) //channel 放入timestamp ) func (c *Config) reload() { ticker := time.NewTicker(CheckInterval) defer ticker.Stop() for { select { case <-c.ctx.Done(): close(routeNotify) return case <-ticker.C: if f, err := os.Stat(c.Route.FilePath); err != nil { fmt.Println(err) } else if f.ModTime().Unix() != c.Route.LastModifyTime { if c.Route.LastModifyTime == 0 { c.Route.LastModifyTime = f.ModTime().Unix() } else { routeAtomic.Store(c.loadConfig()) routeNotify <- f.ModTime().Unix() fmt.Println("配置文件發(fā)生變化") } } } } } func (c *Config) loadConfig() *APIConf { if fp, err := ioutil.ReadFile(c.Route.FilePath); err != nil { fmt.Println(err) return nil } else { route := new(APIConf) if err := yaml.Unmarshal(fp, &route); err != nil { return nil } return route } }
定時(shí)器監(jiān)聽(tīng)文件的修改時(shí)間與LastModifyTime是否相同,如果不同,則
package global var ( APIconfig = new(APIConf) )
package global type ServiceConf struct { Server struct { Env string `yaml:"env"` Host string `yaml:"host"` Port string `yaml:"port"` } `yaml:"server"` } type APIConf struct { Service ServiceConf `yaml:"service"` }
mian
package main import ( "dyconfig/global" "fmt" "github.com/gin-gonic/gin" ) func main() { if conf, err := global.NewConfig(); err != nil { // 初始化配置 fmt.Println(err) } else { defer conf.Stop() } gin.SetMode(gin.DebugMode) r := gin.Default() r.GET("/ping", func(context *gin.Context) { fmt.Println("當(dāng)前host是: ", global.APIconfig.Service.Server.Host) fmt.Println("當(dāng)前port是: ", global.APIconfig.Service.Server.Port) context.JSON( 200, gin.H{ "host": global.APIconfig.Service.Server.Host, "port": &global.APIconfig.Service.Server.Port, }) }) port := global.APIconfig.Service.Server.Port fmt.Println("當(dāng)前host是: ", global.APIconfig.Service.Server.Host) fmt.Println("當(dāng)前port是: ", global.APIconfig.Service.Server.Port) port = ":" + port _ = r.Run(port) }
調(diào)用示例
1.第一次調(diào)用,port為9902
2. 修改config ,port為9903
到此這篇關(guān)于Go語(yǔ)言實(shí)現(xiàn)配置熱加載的方法分享的文章就介紹到這了,更多相關(guān)Go語(yǔ)言配置熱加載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang gorm 結(jié)構(gòu)體的表字段缺省值設(shè)置方式
這篇文章主要介紹了golang gorm 結(jié)構(gòu)體的表字段缺省值設(shè)置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12Go項(xiàng)目與Docker結(jié)合實(shí)現(xiàn)高效部署深入探究
在現(xiàn)代軟件開(kāi)發(fā)中,使用Docker部署應(yīng)用程序已經(jīng)成為一種標(biāo)準(zhǔn)實(shí)踐,本文將深入探討如何將Go項(xiàng)目與Docker結(jié)合,實(shí)現(xiàn)高效、可靠的部署過(guò)程,通過(guò)詳細(xì)的步驟和豐富的示例,你將能夠迅速掌握這一流程2023-12-12Go在GoLand中引用github.com中的第三方包具體步驟
這篇文章主要給大家介紹了關(guān)于Go在GoLand中引用github.com中第三方包的具體步驟,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Go具有一定的參考價(jià)值,需要的朋友可以參考下2024-01-01GO語(yǔ)言gin框架實(shí)現(xiàn)管理員認(rèn)證登陸接口
這篇文章主要介紹了GO語(yǔ)言gin框架實(shí)現(xiàn)管理員認(rèn)證登陸接口,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10