配置读取
定义好名称为 redis.conf
bind 0.0.0.0
port 6379
databases 16
appendonly yes
appendfilename appendonly.aof
- 先通过 os.Open() 打开文件流
- 创建配置文件对象 ServerProperties
- 将读取到的数据存入到 Map 结构中
- 通过 reflect.TypeOf 和 reflect.ValueOf 获取到反射对象
- 遍历类型的字段通过反射获取到字段的名称,再去 Map 中获取到数据设置到对应的数据中
// ServerProperties 定义全局的配置对象
type ServerProperties struct {
Bind string `cfg:"bind"` //绑定ip地址
Port int `cfg:"port"` //端口
AppendOnly bool `cfg:"appendonly"` //是否开启aof
AppendFilename string `cfg:"appendfilename"`//aof名称的名称
AppendFsync string `cfg:"appendfsync"`
MaxClients int `cfg:"maxclients"` //最大客户端数量
RequirePass string `cfg:"requirepass"` //是否要求密码
Databases int `cfg:"databases"` //数据库的数量
RDBFilename string `cfg:"dbfilename"` //rdb文件的名称
MasterAuth string `cfg:"masterauth"` //master角色验证密码
SlaveAnnouncePort int `cfg:"slave-announce-port"`
SlaveAnnounceIP string `cfg:"slave-announce-ip"`
ReplTimeout int `cfg:"repl-timeout"`
Peers []string `cfg:"peers"`
Self string `cfg:"self"`
}
// Properties 全局配置持有对象
var Properties *ServerProperties
// init 初始化服务端的配置信息,设置默认绑定地址和端口
func init() {
// 默认配置对象
Properties = &ServerProperties{
Bind: "127.0.0.1",
Port: 6379,
AppendOnly: false,
}
}
// parse 将文件解析为配置对象
func parse(src io.Reader) *ServerProperties {
config := &ServerProperties{}
// 创建map
rawMap := make(map[string]string)
//获取到扫描器
scanner := bufio.NewScanner(src)
for scanner.Scan() {
line := scanner.Text()
if len(line) > 0 && strings.TrimLeft(line, " ")[0] == '#' {
continue
}
pivot := strings.IndexAny(line, " ")
if pivot > 0 && pivot < len(line)-1 { // separator found
key := line[0:pivot]
value := strings.Trim(line[pivot+1:], " ")
rawMap[strings.ToLower(key)] = value
}
}
//打印err
if err := scanner.Err(); err != nil {
logger.Fatal(err)
}
// 通过反射解析配置名称跟配置对象对应上
t := reflect.TypeOf(config)
v := reflect.ValueOf(config)
//获取到字段的数量
n := t.Elem().NumField()
for i := 0; i < n; i++ {
//通过反射获取到字段的类型
field := t.Elem().Field(i)
//获取到实际的字段操作对象
fieldVal := v.Elem().Field(i)
//获取到cfg的标签,获取到对应配置文件中的配置名称
key, ok := field.Tag.Lookup("cfg")
if !ok || strings.TrimLeft(key, " ") == "" {
key = field.Name
}
//将配置的key存储到map中
value, ok := rawMap[strings.ToLower(key)]
if ok {
// 获取到对应字段的类型
switch field.Type.Kind() {
case reflect.String:
fieldVal.SetString(value)
case reflect.Int:
intValue, err := strconv.ParseInt(value, 10, 64)
if err == nil {
fieldVal.SetInt(intValue)
}
case reflect.Bool:
boolValue := "yes" == value
fieldVal.SetBool(boolValue)
case reflect.Slice:
//将逗号隔开的字符串解析为 Slice切片
if field.Type.Elem().Kind() == reflect.String {
slice := strings.Split(value, ",")
fieldVal.Set(reflect.ValueOf(slice))
}
}
}
}
return config
}
// SetupConfig 设置配置,根据配置文件的名称打开文件路径
func SetupConfig(configFilename string) {
file, err := os.Open(configFilename)
if err != nil {
panic(err)
}
//方法退出时关闭文件
defer func(file *os.File) {
_ = file.Close()
}(file)
//解析文件成为 Properties 对象
Properties = parse(file)
}