一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語(yǔ)言編程技術(shù)及教程分享平臺(tái)!
分類導(dǎo)航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務(wù)器之家 - 腳本之家 - Golang - 使用Go語(yǔ)言實(shí)現(xiàn)配置文件熱加載功能

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

2020-05-14 10:09python修行路 Golang

這篇文章主要介紹了使用Go語(yǔ)言實(shí)現(xiàn)配置文件熱加載功能,以及配置文件熱加載包的實(shí)現(xiàn)思路,需要的朋友可以參考下

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

這次就自己實(shí)現(xiàn)一個(gè)配置文件的熱加載功能的包,并通過(guò)一個(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)為:

?
1
2
├── config.go
└── config_notify.go

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

config_notify.go的代碼相對(duì)來(lái)說(shuō)比較簡(jiǎn)單,我們先看看這個(gè)代碼:

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

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

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

?
1
2
3
4
5
6
7
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):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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{
   // 表示讀文件出問(wèn)題
   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,"=") // 通過(guò)=進(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中。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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è)問(wèn)題需要注意,就是在配置文件中存放數(shù)據(jù)的時(shí)候應(yīng)該是如下格式存儲(chǔ)

?
1
2
3
4
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è)試代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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()
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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)我們更改配置文件后,程序中的配置文件也被重新加載

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

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

總結(jié)

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

原文鏈接:https://www.cnblogs.com/zhaof/p/8593204.html

延伸 · 閱讀

精彩推薦
  • Golanggo日志系統(tǒng)logrus顯示文件和行號(hào)的操作

    go日志系統(tǒng)logrus顯示文件和行號(hào)的操作

    這篇文章主要介紹了go日志系統(tǒng)logrus顯示文件和行號(hào)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧...

    SmallQinYan12302021-02-02
  • Golanggolang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法

    golang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法

    今天小編就為大家分享一篇golang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧 ...

    李浩的life12792020-05-27
  • GolangGolang中Bit數(shù)組的實(shí)現(xiàn)方式

    Golang中Bit數(shù)組的實(shí)現(xiàn)方式

    這篇文章主要介紹了Golang中Bit數(shù)組的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧...

    天易獨(dú)尊11682021-06-09
  • Golanggolang 通過(guò)ssh代理連接mysql的操作

    golang 通過(guò)ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過(guò)ssh代理連接mysql的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧...

    a165861639710342021-03-08
  • Golanggolang如何使用struct的tag屬性的詳細(xì)介紹

    golang如何使用struct的tag屬性的詳細(xì)介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細(xì)介紹,從例子說(shuō)起,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看...

    Go語(yǔ)言中文網(wǎng)11352020-05-21
  • GolangGolang通脈之?dāng)?shù)據(jù)類型詳情

    Golang通脈之?dāng)?shù)據(jù)類型詳情

    這篇文章主要介紹了Golang通脈之?dāng)?shù)據(jù)類型,在編程語(yǔ)言中標(biāo)識(shí)符就是定義的具有某種意義的詞,比如變量名、常量名、函數(shù)名等等,Go語(yǔ)言中標(biāo)識(shí)符允許由...

    4272021-11-24
  • Golanggo語(yǔ)言制作端口掃描器

    go語(yǔ)言制作端口掃描器

    本文給大家分享的是使用go語(yǔ)言編寫的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。 ...

    腳本之家3642020-04-25
  • Golanggolang的httpserver優(yōu)雅重啟方法詳解

    golang的httpserver優(yōu)雅重啟方法詳解

    這篇文章主要給大家介紹了關(guān)于golang的httpserver優(yōu)雅重啟的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,...

    helight2992020-05-14
主站蜘蛛池模板: 性欧美黑人巨大喷潮xxoo | 脱女学小内内摸出水网站免费 | 毛片免费的 | 粗又长好猛好爽视频 | aaa在线| 99国产精品免费观看视频 | 午夜福到在线2019 | 欧美视频在线一区 | 精品视频久久久久 | 免费国产白棉袜踩踏区域 | 日韩欧美一区二区三区免费观看 | 91制片在线观看 | 调教女帝 | 日韩毛片免费 | 国产91在线免费 | 日b视频免费 | 痴mu动漫成年动漫在线观看 | 久久精品动漫99精品动漫 | 香蕉久久ac一区二区三区 | 青草久久精品亚洲综合专区 | 性欧美13处丶14处 | 福利入口在线观看 | 热久久天天拍天天拍热久久2018 | 国产-第1页-草草影院 | xxxx成人 | 双性受合不垅腿攻np | 免费毛片大全 | 欧美高清在线不卡免费观看 | 精品久久成人免费第三区 | 51精品| 好湿好紧好大野战 | 精品久久久久久 | 91免费在线播放 | porno中国xxxxx| 古装一级无遮挡毛片免费观看 | 国产码一区二区三区 | 日本高清视频在线免费观看 | 免费视频一级片 | 外国老少性配 | 精品久久伦理中文字幕 | 乌克兰粉嫩摘花第一次 |