婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識(shí)庫 > 使用Go語言實(shí)現(xiàn)配置文件熱加載功能

使用Go語言實(shí)現(xiàn)配置文件熱加載功能

熱門標(biāo)簽:阿里云ai電話機(jī)器人 釘釘有地圖標(biāo)注功能嗎 濱州自動(dòng)電銷機(jī)器人排名 惠州電銷防封電話卡 浙江高頻外呼系統(tǒng)多少錢一個(gè)月 汕頭小型外呼系統(tǒng) 建造者2地圖標(biāo)注 鄭州亮點(diǎn)科技用的什么外呼系統(tǒng) 黃岡人工智能電銷機(jī)器人哪個(gè)好

 說到配置文件熱加載,這個(gè)功能在很多框架中都提供了,如beego,實(shí)現(xiàn)的效果就是當(dāng)你修改文件后,會(huì)把你修改后的配置重新加載到配置文件中,而不用重啟程序,這個(gè)功能在日常中還是非常實(shí)用的,畢竟很多時(shí)候,線上的配置文件不是想改就能改的。

這次就自己實(shí)現(xiàn)一個(gè)配置文件的熱加載功能的包,并通過一個(gè)簡單的例子對(duì)完成的包進(jìn)行使用驗(yàn)證

配置文件熱加載包的是實(shí)現(xiàn)

其實(shí)整體的思路還是比較簡單的,當(dāng)獲取配置文件內(nèi)容后,會(huì)開啟一個(gè)goroutine,去 循環(huán)讀配置文件,當(dāng)然這里不可能不限制的一直循環(huán),而是設(shè)置了一個(gè)定時(shí)器,定時(shí)去讀文件,根據(jù)文件的修改時(shí)間是否變化,從而確定是否重新reload配置文件

實(shí)現(xiàn)的config 包的文件結(jié)構(gòu)為:

├── config.go
└── config_notify.go

config.go:代碼的主要處理邏輯
config_notify.go:主要定義了一個(gè)接口,用于當(dāng)文件修改時(shí)間變化的時(shí)候執(zhí)行回調(diào)

config_notify.go的代碼相對(duì)來說比較簡單,我們先看看這個(gè)代碼:

package config
// 定義一個(gè)通知的接口
type Notifyer interface {
 Callback(*Config)
}

這樣當(dāng)我們實(shí)現(xiàn)了Callback這個(gè)方法的時(shí)候,我們就實(shí)現(xiàn)了Notifyer這個(gè)接口,具體的調(diào)用在后面會(huì)說

在config.go中我們頂一個(gè)了一個(gè)結(jié)構(gòu)體:

type Config struct {
 filename string
 lastModifyTime int64
 data map[string]string
 rwLock sync.RWMutex
 notifyList []Notifyer
}

結(jié)構(gòu)體中主要包含幾個(gè)字段:

filename:配置文件名字
lastModifyTime:配置文件的最后修改時(shí)間
data:用于將從配置文件中讀取的內(nèi)容存儲(chǔ)為map
rwlock:讀寫鎖
notifyList:用于將調(diào)用該包的程序追加到切片中,用于通知調(diào)用上面在config_notify.go定義的callback回調(diào)函數(shù)

關(guān)于讀取配置文件中的內(nèi)容并存儲(chǔ)到map中,這里定義了一個(gè)方法實(shí)現(xiàn):

func (c *Config) parse()(m map[string]string,err error){
 // 讀文件并或?qū)⑽募械臄?shù)據(jù)以k/v的形式存儲(chǔ)到map中
 m = make(map[string]string,1024)
 file,err := os.Open(c.filename)
 if err != nil{
  return
 }
 var lineNo int
 reader := bufio.NewReader(file)
 for{
  // 一行行的讀文件
  line,errRet := reader.ReadString('\n')
  if errRet == io.EOF{
   // 表示讀到文件的末尾
   break
  }
  if errRet != nil{
   // 表示讀文件出問題
   err = errRet
   return
  }
  lineNo++
  line = strings.TrimSpace(line) // 取出空格
  if len(line) == 0 || line[0] == '\n' || line[0] == '+' || line[0] == ';'{
   // 當(dāng)前行為空行或者是注釋行等
   continue
  }
  arr := strings.Split(line,"=") // 通過=進(jìn)行切割取出k/v結(jié)構(gòu)
  if len(arr) == 0{
   fmt.Printf("invalid config,line:%d\n",lineNo)
   continue
  }
  key := strings.TrimSpace(arr[0])
  if len(key) == 0{
   fmt.Printf("invalid config,line:%d\n",lineNo)
   continue
  }
  if len(arr) == 1{
   m[key] = ""
   continue
  }
  value := strings.TrimSpace(arr[1])
  m[key] = value
 }
 return
}

而最后我們就需要一個(gè)定時(shí)器,每隔一段時(shí)間判斷配置文件的最后修改時(shí)間是否變化,如果變化則重新讀取一次文件并將文件內(nèi)容存儲(chǔ)到map中。

func (c *Config) reload(){
 // 這里啟動(dòng)一個(gè)定時(shí)器,每5秒重新加載一次配置文件
 ticker := time.NewTicker(time.Second*5)
 for _ = range ticker.C{
  func(){
   file,err := os.Open(c.filename)
   if err != nil{
    fmt.Printf("open %s failed,err:%v\n",c.filename,err)
    return
   }
   defer file.Close()
   fileInfo,err := file.Stat()
   if err != nil{
    fmt.Printf("stat %s failed,err:%v\n",c.filename,err)
    return
   }
   curModifyTime := fileInfo.ModTime().Unix()
   fmt.Printf("%v --- %v\n",curModifyTime,c.lastModifyTime)
   //判斷文件的修改時(shí)間是否大于最后一次修改時(shí)間
   if curModifyTime > c.lastModifyTime{
    m,err := c.parse()
    if err != nil{
     fmt.Println("parse failed,err:",err)
     return
    }
    c.rwLock.Lock()
    c.data = m
    c.rwLock.Unlock()
    for _, n:=range c.notifyList{
     n.Callback(c)
    }
    c.lastModifyTime = curModifyTime
   }
  }()
 }

關(guān)于config完整的代碼地址:https://github.com/pythonsite/go_simple_code/tree/master/config

一個(gè)演示上述包的例子

這里一個(gè)簡單的例子,代碼的邏輯也非常簡單就是寫一個(gè)循環(huán)從配置文件讀取配置信息,當(dāng)然這里是為了測(cè)試效果,寫成了循環(huán)。這里有個(gè)問題需要注意,就是在配置文件中存放數(shù)據(jù)的時(shí)候應(yīng)該是如下格式存儲(chǔ)

listen_addr = localhost
server_port = 1000
# Nginx addr
nginx_addr = 192.168.1.2:9090

測(cè)試代碼的主要結(jié)構(gòu)如下:

├── config.conf
└── main.go

config.conf為配置文件
main.go 為主要測(cè)試代碼

type AppConfig struct {
 port int
 nginxAddr string
}
type AppconfigMgr struct {
 config atomic.Value
}
var appConfigMgr = AppconfigMgr{}
func(a *AppconfigMgr)Callback(conf *config.Config){
 var appConfig = AppConfig{}
 port,err := conf.GetInt("server_port")
 if err != nil{
  fmt.Println("get port failed,err:",err)
  return
 }
 appConfig.port = port
 fmt.Println("port:",appConfig.port)
 nginxAddr,err := conf.GetString("nginx_addr")
 if err != nil{
  fmt.Println("get nginx addr failed,err:",err)
  return
 }
 appConfig.nginxAddr = nginxAddr
 fmt.Println("nginx addr :",appConfig.nginxAddr)
 appConfigMgr.config.Store(appConfig)
}
func run(){
 for {
  // 每5秒打印一次數(shù)據(jù),查看自己更改配置文件后是否可以熱刷新
  appConfig := appConfigMgr.config.Load().(*AppConfig)
  fmt.Println("port:",appConfig.port)
  fmt.Println("nginx addr:",appConfig.nginxAddr)
  time.Sleep(5* time.Second)
 }
}
func main() {
 conf,err := config.NewConfig("/Users/zhaofan/go_project/src/go_dev/13/config_test/config.conf")
 if err != nil{
  fmt.Println("parse config failed,err:",err)
  return
 }
 //打開文件獲取內(nèi)容后,將自己加入到被通知的切片中
 conf.AddNotifyer(appConfigMgr)
 var appConfig = AppConfig{}
 appConfig.port,err = conf.GetInt("server_port")
 if err != nil{
  fmt.Println("get port failed,err:",err)
  return
 }
 fmt.Println("port:",appConfig.port)
 appConfig.nginxAddr,err = conf.GetString("nginx_addr")
 if err != nil{
  fmt.Println("get nginx addr failed,err:",err)
  return
 }
 fmt.Println("nginx addr:",appConfig.nginxAddr)
 appConfigMgr.config.Store(appConfig)
 run()
}

上面代碼中有一段代碼非常重要:

func(a *AppconfigMgr)Callback(conf *config.Config){
 var appConfig = AppConfig{}
 port,err := conf.GetInt("server_port")
 if err != nil{
  fmt.Println("get port failed,err:",err)
  return
 }
 appConfig.port = port
 fmt.Println("port:",appConfig.port)
 nginxAddr,err := conf.GetString("nginx_addr")
 if err != nil{
  fmt.Println("get nginx addr failed,err:",err)
  return
 }
 appConfig.nginxAddr = nginxAddr
 fmt.Println("nginx addr :",appConfig.nginxAddr)
 appConfigMgr.config.Store(appConfig)
}

這里我們實(shí)現(xiàn)了Callback方法,同時(shí)就實(shí)現(xiàn)了我們?cè)赾onfig包中定義的那個(gè)接口

測(cè)試效果如下,當(dāng)我們更改配置文件后,程序中的配置文件也被重新加載

完整的測(cè)試代碼地址:https://github.com/pythonsite/go_simple_code/tree/master/config_test

總結(jié)

以上所述是小編給大家介紹的使用Go語言實(shí)現(xiàn)配置文件熱加載功能,希望對(duì)大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的!

您可能感興趣的文章:
  • MongoDB 3.4配置文件避免入坑的注意事項(xiàng)
  • MongoDB的安裝及配置文件選項(xiàng)全解
  • 在Django中同時(shí)使用多個(gè)配置文件的方法
  • python用ConfigObj讀寫配置文件的實(shí)現(xiàn)代碼

標(biāo)簽:泰安 阿壩 昭通 駐馬店 東營 滄州 瀘州 晉中

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《使用Go語言實(shí)現(xiàn)配置文件熱加載功能》,本文關(guān)鍵詞  使用,語言,實(shí)現(xiàn),配置文件,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《使用Go語言實(shí)現(xiàn)配置文件熱加載功能》相關(guān)的同類信息!
  • 本頁收集關(guān)于使用Go語言實(shí)現(xiàn)配置文件熱加載功能的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    主站蜘蛛池模板: 凉山| 奉化市| 华池县| 湄潭县| 伊金霍洛旗| 确山县| 宜良县| 镇宁| 乌鲁木齐市| 乳山市| 黄平县| 理塘县| 凤凰县| 塔河县| 侯马市| 广安市| 彰武县| 张掖市| 攀枝花市| 屏东市| 兴文县| 桐梓县| 涿州市| 大埔区| 荣昌县| 监利县| 丰城市| 长治县| 东丰县| 丹江口市| 庆安县| 横山县| 无锡市| 荣昌县| 卢龙县| 芜湖市| 贵德县| 富源县| 龙井市| 宜宾县| 芜湖市|