面试题答案
一键面试实现思路
- 选择配置文件格式:常见的如JSON、YAML等,Go标准库对JSON支持良好,也可使用第三方库处理YAML等格式。
- 定期读取配置文件:使用Go的
time.Ticker
定期检查配置文件修改时间,若文件更新则重新读取。 - 使用通道(Channel)进行通知:当检测到配置文件更新时,通过通道通知业务逻辑,使其能及时做出调整。
- 实现配置结构体:定义一个结构体来表示配置信息,方便在程序中使用。
关键代码片段
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"time"
)
// Config 配置结构体
type Config struct {
ServerAddr string `json:"server_addr"`
DatabaseDSN string `json:"database_dsn"`
// 其他配置字段
}
var (
config Config
configMutex = new(sync.RWMutex)
configUpdate = make(chan struct{})
)
// loadConfig 加载配置文件
func loadConfig() error {
data, err := ioutil.ReadFile("config.json")
if err != nil {
return err
}
return json.Unmarshal(data, &config)
}
// watchConfig 监控配置文件变化
func watchConfig() {
lastModTime := time.Time{}
for {
fileInfo, err := os.Stat("config.json")
if err != nil {
fmt.Printf("Error stating config file: %v\n", err)
time.Sleep(5 * time.Second)
continue
}
if fileInfo.ModTime().After(lastModTime) {
if err := loadConfig(); err == nil {
fmt.Println("Config reloaded successfully")
lastModTime = fileInfo.ModTime()
configUpdate <- struct{}{}
} else {
fmt.Printf("Error reloading config: %v\n", err)
}
}
time.Sleep(5 * time.Second)
}
}
处理配置变更带来的业务逻辑调整
- 在业务逻辑中监听通道:在启动业务逻辑的goroutine中,监听
configUpdate
通道。
func main() {
if err := loadConfig(); err != nil {
fmt.Printf("Error loading config: %v\n", os.Exit(1))
}
go watchConfig()
go func() {
for {
select {
case <-configUpdate:
configMutex.Lock()
// 根据新的配置更新业务逻辑相关的设置,例如重新连接数据库
fmt.Println("Updating business logic with new config")
configMutex.Unlock()
}
}
}()
// 其他业务逻辑
select {}
}
- 使用互斥锁(Mutex):由于配置可能在多个goroutine中访问,使用互斥锁保护配置结构体,确保数据一致性。在读取配置时使用读锁(
RLock
),在更新配置和根据新配置调整业务逻辑时使用写锁(Lock
)。
通过上述方式,可以优雅地实现Go服务程序中配置文件的热加载以及对配置变更带来的业务逻辑调整。