背景
今天分享一个利用reflect
在实际项目中比较省时、代码简洁且高效的方法-服务配置自动初始化的方法。 我们在起一个Web项目时,常常都是直接使用开源的一些框架或组建,然后在我们自己的项目中要使用之前按照该框架或组建提供的帮助文档一个一个进行相应的初始化配置。也许我们只引用其中一两个,这样写都还能忍受,可是如果这个服务会引用更多的呢?
效果
- 代码简洁化
- 接入第三方库就如搭积木一样,模块化,随取随用
- 可维护性高
干货
下面,我们就来利用reflect
实现该功能。
思路
磨刀不误砍柴工,我们先整理好一个简单思路,然后再尝试实现它,这样就简单了。
- 从远端配置服务或本地获取到我们需要初始化的配置
- 解析配置中的数据
- 判断配置中元素是否有实现我们指定方法,如果有就执行它,没有就跳过 没错,用语言描述就这么三句话,就这么简单。
获取配置
服务要启动,获取配置要么从远端配置服务拉取,要么从本地读取,就以常见的json格式作为我们本次举例的配置格式吧。
{
"ginx": {
"listen_port": 8080
},
"conn_timeout":2
}
复制代码
既然是json化的配置,那我们就需要一个struct
结构体来对配置进行反解析,这个貌似没什么好说的。
type Cfg struct {
ConnTimeout int `json:"conn_timeout"`
Ginx *ginx.Ginx `json:"ginx"`
// other config
}
复制代码
其中ginx.Ginx
是我们自定义的一个结构体。
查找结构体中是否包含某方法
type ICanInit interface {
Init()
}
func InitialRoot(rv reflect.Value) {
tpe := rv.Type()
for i := 0; i < tpe.NumField(); i++ {
value := rv.Field(i)
if conf, ok := value.Interface().(ICanInit); ok {
conf.Init()
}
}
}
复制代码
对,上面的这个就是判断某结构体中是否已实现Init()
方法,有的话就执行它。这个就是实现这个功能的核心,是不是很简单?哈哈。 我们在实现这个功能之前,只需要对配置结构体进行一下简单的类型判断就OK了。
总结
reflect
的用处远不止于此,多总结,然后付诸行动。
如有兴趣,源码在此