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

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

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

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

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

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

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

實現(xiàn)的config 包的文件結構為:

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

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

config_notify.go的代碼相對來說比較簡單,我們先看看這個代碼:

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

這樣當我們實現(xiàn)了Callback這個方法的時候,我們就實現(xiàn)了Notifyer這個接口,具體的調用在后面會說

在config.go中我們頂一個了一個結構體:

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

結構體中主要包含幾個字段:

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

關于讀取配置文件中的內容并存儲到map中,這里定義了一個方法實現(xiàn):

func (c *Config) parse()(m map[string]string,err error){
 // 讀文件并或將文件中的數(shù)據以k/v的形式存儲到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] == ';'{
   // 當前行為空行或者是注釋行等
   continue
  }
  arr := strings.Split(line,"=") // 通過=進行切割取出k/v結構
  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
}

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

func (c *Config) reload(){
 // 這里啟動一個定時器,每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)
   //判斷文件的修改時間是否大于最后一次修改時間
   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
   }
  }()
 }

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

一個演示上述包的例子

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

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

測試代碼的主要結構如下:

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

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

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ù)據,查看自己更改配置文件后是否可以熱刷新
  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
 }
 //打開文件獲取內容后,將自己加入到被通知的切片中
 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)
}

這里我們實現(xiàn)了Callback方法,同時就實現(xiàn)了我們在config包中定義的那個接口

測試效果如下,當我們更改配置文件后,程序中的配置文件也被重新加載

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

總結

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

相關文章

  • go語言操作redis連接池的方法

    go語言操作redis連接池的方法

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

    GO的基礎知識掃盲注意事項

    這篇文章主要介紹了GO的基礎知識注意事項,本文是GO語言小白的掃盲文,主要講解了go語言的基本知識,GO程序目錄結構,GO程序包的導入與別名運用,GO內置關鍵字,GO注釋方法需要的朋友可以參考下
    2022-12-12
  • Go語言如何使用golang-jwt/jwt/v4進行JWT鑒權詳解

    Go語言如何使用golang-jwt/jwt/v4進行JWT鑒權詳解

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

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

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

    用go寫的五子棋預測算法的實現(xiàn)

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

    在Golang中使用iota案例詳解

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

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

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

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

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

    Go語言中Seeker接口的用法詳解

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

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

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

最新評論