-
Notifications
You must be signed in to change notification settings - Fork 1
/
yaml.go
269 lines (231 loc) · 6.93 KB
/
yaml.go
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
package config
import (
"github.com/wjshen/gophrame/core/command"
"github.com/wjshen/gophrame/core/container"
"github.com/wjshen/gophrame/core/global"
"github.com/wjshen/gophrame/core/logger"
"github.com/wjshen/gophrame/errors"
"io/ioutil"
"sync"
"time"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"gopkg.in/yaml.v3"
)
// 由于 vipver 包本身对于文件的变化事件有一个bug,相关事件会被回调两次
// 常年未彻底解决,相关的 issue 清单:https://github.com/spf13/viper/issues?q=OnConfigChange
// 设置一个内部全局变量,记录配置文件变化时的时间点,如果两次回调事件事件差小于1秒,我们认为是第二次回调事件,而不是人工修改配置文件
// 这样就避免了 viper 包的这个bug
type IYmlConfig interface {
ConfigFileChangeListen()
Clone(fileName string) IYmlConfig
Get(keyName string) interface{}
GetString(keyName string) string
GetBool(keyName string) bool
GetInt(keyName string) int
GetInt32(keyName string) int32
GetInt64(keyName string) int64
GetFloat64(keyName string) float64
GetDuration(keyName string) time.Duration
GetStringSlice(keyName string) []string
}
var lastChangeTime time.Time
var containerFactory = container.CreateContainersFactory()
var ConfigYml IYmlConfig
func init() {
lastChangeTime = time.Now()
}
func InitYamlConfig(out interface{}) error {
yamlFile := "application"
if command.Profile != "" {
yamlFile += "-" + command.Profile
} else {
switch command.Mode {
case "debug":
yamlFile += "-dev"
case "production":
yamlFile += "-prod"
}
}
logger.Info("Load configuration file: ", yamlFile+".yml")
ConfigYml = CreateYamlFactory(yamlFile)
ConfigYml.ConfigFileChangeListen()
//1. 读取文件
data, err := ioutil.ReadFile(global.BasePath + "/conf/" + yamlFile + ".yml")
if err == nil {
err = yaml.Unmarshal(data, out)
}
if err != nil {
logger.Error(err.Error())
}
return err
}
// CreateYamlFactory 创建一个yaml配置文件工厂
// 参数设置为可变参数的文件名,这样参数就可以不需要传递,如果传递了多个,我们只取第一个参数作为配置文件名
func CreateYamlFactory(fileName ...string) IYmlConfig {
yamlConfig := viper.New()
// 配置文件所在目录
yamlConfig.AddConfigPath(global.BasePath + "/conf")
// 需要读取的文件名,默认为:application
if len(fileName) == 0 {
yamlConfig.SetConfigName("application")
} else {
yamlConfig.SetConfigName(fileName[0])
}
//设置配置文件类型(后缀)为 yml
yamlConfig.SetConfigType("yml")
if err := yamlConfig.ReadInConfig(); err != nil {
logger.Fatal(errors.ERROR_CONFIG_INIT_FAIL, errors.GetErrorMessage(errors.ERROR_CONFIG_INIT_FAIL), err.Error())
}
return &ymlConfig{
viper: yamlConfig,
mu: new(sync.Mutex),
}
}
type ymlConfig struct {
viper *viper.Viper
mu *sync.Mutex
}
// ConfigFileChangeListen 监听文件变化
func (y *ymlConfig) ConfigFileChangeListen() {
y.viper.OnConfigChange(func(changeEvent fsnotify.Event) {
if time.Since(lastChangeTime).Seconds() >= 1 {
if changeEvent.Op.String() == "WRITE" {
y.clearCache()
lastChangeTime = time.Now()
for _, f := range configChangeCallbacks {
f()
}
}
}
})
y.viper.WatchConfig()
}
// keyIsCache 判断相关键是否已经缓存
func (y *ymlConfig) keyIsCache(keyName string) bool {
if _, exists := containerFactory.KeyIsExists(global.ConfigKeyPrefix + keyName); exists {
return true
} else {
return false
}
}
// 对键值进行缓存
func (y *ymlConfig) cache(keyName string, value interface{}) bool {
// 避免瞬间缓存键、值时,程序提示键名已经被注册的日志输出
y.mu.Lock()
defer y.mu.Unlock()
if _, exists := containerFactory.KeyIsExists(global.ConfigKeyPrefix + keyName); exists {
return true
}
return containerFactory.Set(global.ConfigKeyPrefix+keyName, value)
}
// 通过键获取缓存的值
func (y *ymlConfig) getValueFromCache(keyName string) interface{} {
return containerFactory.Get(global.ConfigKeyPrefix + keyName)
}
// 清空已经缓存的配置项信息
func (y *ymlConfig) clearCache() {
containerFactory.FuzzyDelete(global.ConfigKeyPrefix)
}
// Clone 允许 clone 一个相同功能的结构体
func (y *ymlConfig) Clone(fileName string) IYmlConfig {
// 这里存在一个深拷贝,需要注意,避免拷贝的结构体操作对原始结构体造成影响
var ymlC = *y
var ymlConfViper = *(y.viper)
(&ymlC).viper = &ymlConfViper
(&ymlC).viper.SetConfigName(fileName)
if err := (&ymlC).viper.ReadInConfig(); err != nil {
logger.Error(errors.ERROR_CONFIG_INIT_FAIL, errors.GetErrorMessage(errors.ERROR_CONFIG_INIT_FAIL), err.Error())
}
return &ymlC
}
// Get 一个原始值
func (y *ymlConfig) Get(keyName string) interface{} {
if y.keyIsCache(keyName) {
return y.getValueFromCache(keyName)
} else {
value := y.viper.Get(keyName)
y.cache(keyName, value)
return value
}
}
// GetString 字符串格式返回值
func (y *ymlConfig) GetString(keyName string) string {
if y.keyIsCache(keyName) {
return y.getValueFromCache(keyName).(string)
} else {
value := y.viper.GetString(keyName)
y.cache(keyName, value)
return value
}
}
// GetBool 布尔格式返回值
func (y *ymlConfig) GetBool(keyName string) bool {
if y.keyIsCache(keyName) {
return y.getValueFromCache(keyName).(bool)
} else {
value := y.viper.GetBool(keyName)
y.cache(keyName, value)
return value
}
}
// GetInt 整数格式返回值
func (y *ymlConfig) GetInt(keyName string) int {
if y.keyIsCache(keyName) {
return y.getValueFromCache(keyName).(int)
} else {
value := y.viper.GetInt(keyName)
y.cache(keyName, value)
return value
}
}
// GetInt32 整数格式返回值
func (y *ymlConfig) GetInt32(keyName string) int32 {
if y.keyIsCache(keyName) {
return y.getValueFromCache(keyName).(int32)
} else {
value := y.viper.GetInt32(keyName)
y.cache(keyName, value)
return value
}
}
// GetInt64 整数格式返回值
func (y *ymlConfig) GetInt64(keyName string) int64 {
if y.keyIsCache(keyName) {
return y.getValueFromCache(keyName).(int64)
} else {
value := y.viper.GetInt64(keyName)
y.cache(keyName, value)
return value
}
}
// GetFloat64 小数格式返回值
func (y *ymlConfig) GetFloat64(keyName string) float64 {
if y.keyIsCache(keyName) {
return y.getValueFromCache(keyName).(float64)
} else {
value := y.viper.GetFloat64(keyName)
y.cache(keyName, value)
return value
}
}
// GetDuration 时间单位格式返回值
func (y *ymlConfig) GetDuration(keyName string) time.Duration {
if y.keyIsCache(keyName) {
return y.getValueFromCache(keyName).(time.Duration)
} else {
value := y.viper.GetDuration(keyName)
y.cache(keyName, value)
return value
}
}
// GetStringSlice 字符串切片数格式返回值
func (y *ymlConfig) GetStringSlice(keyName string) []string {
if y.keyIsCache(keyName) {
return y.getValueFromCache(keyName).([]string)
} else {
value := y.viper.GetStringSlice(keyName)
y.cache(keyName, value)
return value
}
}