欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2018年03月18日 09:22:59   作者:python修行路  
這篇文章主要介紹了使用Go語(yǔ)言實(shí)現(xiàn)配置文件熱加載功能,以及配置文件熱加載包的實(shí)現(xiàn)思路,需要的朋友可以參考下

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

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

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

其實(shí)整體的思路還是比較簡(jiǎn)單的,當(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ì)來說比較簡(jiǎn)單,我們先看看這個(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è)簡(jiǎn)單的例子,代碼的邏輯也非常簡(jiǎn)單就是寫一個(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語(yǔ)言實(shí)現(xiàn)配置文件熱加載功能,希望對(duì)大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的!

相關(guān)文章

  • go語(yǔ)言操作redis連接池的方法

    go語(yǔ)言操作redis連接池的方法

    這篇文章主要介紹了go語(yǔ)言操作redis連接池的方法,涉及Go語(yǔ)言操作radis的技巧,需要的朋友可以參考下
    2015-03-03
  • GO的基礎(chǔ)知識(shí)掃盲注意事項(xiàng)

    GO的基礎(chǔ)知識(shí)掃盲注意事項(xiàng)

    這篇文章主要介紹了GO的基礎(chǔ)知識(shí)注意事項(xiàng),本文是GO語(yǔ)言小白的掃盲文,主要講解了go語(yǔ)言的基本知識(shí),GO程序目錄結(jié)構(gòu),GO程序包的導(dǎo)入與別名運(yùn)用,GO內(nèi)置關(guān)鍵字,GO注釋方法需要的朋友可以參考下
    2022-12-12
  • Go語(yǔ)言如何使用golang-jwt/jwt/v4進(jìn)行JWT鑒權(quán)詳解

    Go語(yǔ)言如何使用golang-jwt/jwt/v4進(jìn)行JWT鑒權(quán)詳解

    最近項(xiàng)目中需要用到鑒權(quán)機(jī)制,golang中jwt可以用,這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言如何使用golang-jwt/jwt/v4進(jìn)行JWT鑒權(quán)的相關(guān)資料,需要的朋友可以參考下
    2022-09-09
  • Golang中的自定義函數(shù)類型詳解

    Golang中的自定義函數(shù)類型詳解

    在 Golang 中,type 關(guān)鍵字用于定義自定義類型,函數(shù)也是一種數(shù)據(jù)類型,因此可以使用 type 關(guān)鍵字來定義函數(shù)類型,本文就給大家詳細(xì)介紹一下Golang中的自定義函數(shù)類型,需要的朋友可以參考下
    2023-07-07
  • 用go寫的五子棋預(yù)測(cè)算法的實(shí)現(xiàn)

    用go寫的五子棋預(yù)測(cè)算法的實(shí)現(xiàn)

    這篇文章主要介紹了用go寫的五子棋預(yù)測(cè)算法的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • 在Golang中使用iota案例詳解

    在Golang中使用iota案例詳解

    在Go語(yǔ)言中,iota是一個(gè)預(yù)定義的標(biāo)識(shí)符,用于在常量聲明中生成連續(xù)的遞增值,iota的值從0開始,每次在常量聲明中使用時(shí)遞增,本就給大家講解一下Golang中iota的使用案例,感興趣的同學(xué)跟著小編一起來看看吧
    2023-07-07
  • 淺談Go中數(shù)字轉(zhuǎn)換字符串的正確姿勢(shì)

    淺談Go中數(shù)字轉(zhuǎn)換字符串的正確姿勢(shì)

    這篇文章主要介紹了淺談Go中數(shù)字轉(zhuǎn)換字符串的正確姿勢(shì),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • golang實(shí)現(xiàn)RPC模塊的示例

    golang實(shí)現(xiàn)RPC模塊的示例

    本文詳細(xì)介紹了在Go語(yǔ)言中如何實(shí)現(xiàn)RPC模塊,包括RPC服務(wù)端和客戶端的構(gòu)建及代碼實(shí)現(xiàn),同時(shí)提到了使用JSON-RPC的方法,通過簡(jiǎn)單的步驟,可以實(shí)現(xiàn)跨進(jìn)程的遠(yuǎn)程過程調(diào)用,感興趣的可以了解一下
    2024-09-09
  • Go語(yǔ)言中Seeker接口的用法詳解

    Go語(yǔ)言中Seeker接口的用法詳解

    Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)中的io包提供了一系列接口,用于處理各種I/O操作,其中Seeker接口在處理大文件或需要隨機(jī)訪問的場(chǎng)景中非常有用,本文將結(jié)合具體案例,詳細(xì)介紹Go語(yǔ)言中io包的Seeker接口的用法,需要的朋友可以參考下
    2024-10-10
  • golang?db事務(wù)的統(tǒng)一封裝的實(shí)現(xiàn)

    golang?db事務(wù)的統(tǒng)一封裝的實(shí)現(xiàn)

    這篇文章主要介紹了golang db事務(wù)的統(tǒng)一封裝的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12

最新評(píng)論