素材巴巴 > 程序开发 >

beego使用及源码解析二(config配置模块)

程序开发 2023-09-06 10:26:40

目录

一.config模块的使用

1.beego使用config解析

2.自由使用beego的config模块

二:beego使用beego的config模块源码解析

三:config模块源码解析


一.config模块的使用

1.beego使用config解析

beego使用自身的config模块,一般就是再目录结构conf下,创建一个app.conf文件,如上图所示,然后配置各个选项即可。

那么我们代码中,如何获取配置文件中对应的值呢?

通过下面的方式即可获取:

func main() {appName :=beego.AppConfig.String("appname")beego.Debug("app name is:", appName)beego.Run()
 }

2.自由使用beego的config模块

我们也可以自由定义其他配置文件,然后使用config模块

func main() {mycfg, err := config.NewConfig("json", "./config.json")if err != nil {beego.Error("new config err:", err)return}mytestData := mycfg.String("mytest")beego.Debug("my test data is:", mytestData)
 }
 

我们可以使用很多格式的配置文件:env,xml,yaml,ini,json等。

二:beego使用beego的config模块源码解析

 

我们在使用的时候一般都是在conf下搞一个app.conf的配置文件,对beego进行配置,beego就能加载这个配置文件,最后在使用时生效。

今天就来梳理这个beego配置到生效的过程。

看到beego/config.go有初始化的配置

func init() {BConfig = newBConfig()var err errorif AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil {panic(err)}workPath, err := os.Getwd()if err != nil {panic(err)}var filename = "app.conf"if os.Getenv("BEEGO_RUNMODE") != "" {filename = os.Getenv("BEEGO_RUNMODE") + ".app.conf"}appConfigPath = filepath.Join(workPath, "conf", filename)if !utils.FileExists(appConfigPath) {appConfigPath = filepath.Join(AppPath, "conf", filename)if !utils.FileExists(appConfigPath) {AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()}return}}if err = parseConfig(appConfigPath); err != nil {panic(err)}
 }

BConfig结构如下

type Config struct {AppName             string //Application nameRunMode             string //Running Mode: dev | prodRouterCaseSensitive boolServerName          stringRecoverPanic        boolRecoverFunc         func(*context.Context)CopyRequestBody     boolEnableGzip          boolMaxMemory           int64EnableErrorsShow    boolEnableErrorsRender  boolListen              ListenWebConfig           WebConfigLog                 LogConfig
 }
 type Listen struct {Graceful          bool // Graceful means use graceful module to start the serverServerTimeOut     int64ListenTCP4        boolEnableHTTP        boolHTTPAddr          stringHTTPPort          intAutoTLS           boolDomains           []stringTLSCacheDir       stringEnableHTTPS       boolEnableMutualHTTPS boolHTTPSAddr         stringHTTPSPort         intHTTPSCertFile     stringHTTPSKeyFile      stringTrustCaFile       stringEnableAdmin       boolAdminAddr         stringAdminPort         intEnableFcgi        boolEnableStdIo       bool // EnableStdIo works with EnableFcgi Use FCGI via standard I/O
 }// WebConfig holds web related config
 type WebConfig struct {AutoRender             boolEnableDocs             boolFlashName              stringFlashSeparator         stringDirectoryIndex         boolStaticDir              map[string]stringStaticExtensionsToGzip []stringTemplateLeft           stringTemplateRight          stringViewsPath              stringEnableXSRF             boolXSRFKey                stringXSRFExpire             intSession                SessionConfig
 }// SessionConfig holds session related config
 type SessionConfig struct {SessionOn                    boolSessionProvider              stringSessionName                  stringSessionGCMaxLifetime         int64SessionProviderConfig        stringSessionCookieLifeTime        intSessionAutoSetCookie         boolSessionDomain                stringSessionDisableHTTPOnly       bool // used to allow for cross domain cookies/javascript cookies.SessionEnableSidInHTTPHeader bool // enable store/get the sessionId into/from http headersSessionNameInHTTPHeader      stringSessionEnableSidInURLQuery   bool // enable get the sessionId from Url Query params
 }// LogConfig holds Log related config
 type LogConfig struct {AccessLogs       boolEnableStaticLogs bool   //log static files requests default: falseAccessLogsFormat string //access log format: JSON_FORMAT, APACHE_FORMAT or empty stringFileLineNum      boolOutputs          map[string]string // Store Adaptor : config
 }

BConfig结构全是运行时有关的配置项。也即所有支持的配置项全在这个结构中了,后面我们在文件中配合的,都需要设置到这个配置对象中才行。首先初始化的时候都会会给一个默认的值。

那么我们配置文件在哪里加载?看代码

func init() {BConfig = newBConfig()var err errorif AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil {panic(err)}workPath, err := os.Getwd()if err != nil {panic(err)}var filename = "app.conf"if os.Getenv("BEEGO_RUNMODE") != "" {filename = os.Getenv("BEEGO_RUNMODE") + ".app.conf"}appConfigPath = filepath.Join(workPath, "conf", filename)if !utils.FileExists(appConfigPath) {appConfigPath = filepath.Join(AppPath, "conf", filename)if !utils.FileExists(appConfigPath) {AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()}return}}if err = parseConfig(appConfigPath); err != nil {panic(err)}
 }
 

在上面的代码中可以看到

先找运行时的路径下的conf/app.conf,如果找不到再找程序所在目录下的conf/app.conf,如果还找不到,那么就给一个空的对象。

如果上面两个路径找到文件了,继续解析。。。咱们继续看代码。

func parseConfig(appConfigPath string) (err error) {AppConfig, err = newAppConfig(appConfigProvider, appConfigPath)if err != nil {return err}return assignConfig(AppConfig)
 }

继续。。。。

func assignConfig(ac config.Configer) error {for _, i := range []interface{}{BConfig, &BConfig.Listen, &BConfig.WebConfig, &BConfig.Log, &BConfig.WebConfig.Session} {assignSingleConfig(i, ac)}....// set the run mode firstif envRunMode := os.Getenv("BEEGO_RUNMODE"); envRunMode != "" {BConfig.RunMode = envRunMode} else if runMode := ac.String("RunMode"); runMode != "" {BConfig.RunMode = runMode}...
 }

注意了,重点到了:这里函数前3行,将配置的结构体,都转为interface{}切片,然后遍历调用了assignSingleConfig,很明显,这个函数,就是要将配置文件中的内容ac,替换到全局配置对象BConfig中,这个函数是替换单个结构体中的各个字段,不能递归替换字段中的字段,所以将BConfig中的所有结构体都单独拿出来。

而这三行后面的其他代码是做啥?阅读代码可看到,函数中后我...省略的代码,也是解析BConfig中的配置项,那么为什么不在assignSingleConfig中一起解析?因为这些单独解析的配置项有自己的优先级,如上面单独拿出来的RunMode,首先从环境变量中获取该配置,如果没有菜从配置文件中获取。

那么,现在我们继续探索assignSingleConfig函数

func assignSingleConfig(p interface{}, ac config.Configer) {// 获取typept := reflect.TypeOf(p)if pt.Kind() != reflect.Ptr {return}// 因为是指针,所以需要获取结构体pt = pt.Elem()if pt.Kind() != reflect.Struct {return}// 获取valuepv := reflect.ValueOf(p).Elem()// 获取字段for i := 0; i < pt.NumField(); i++ {pf := pv.Field(i)if !pf.CanSet() {continue}name := pt.Field(i).Name// 根据字段类型获取配置文件中的对应的配置项switch pf.Kind() {case reflect.String:pf.SetString(ac.DefaultString(name, pf.String()))case reflect.Int, reflect.Int64:pf.SetInt(ac.DefaultInt64(name, pf.Int()))case reflect.Bool:pf.SetBool(ac.DefaultBool(name, pf.Bool()))case reflect.Struct:default://do nothing here}}}

这下可就明白了!

三:config模块源码解析

config采用工厂模式来实现的,

config.go文件中定义了一个接口,然后其他文件中来实现这个接口。并通过函数

func Register(name string, adapter Config) 注册到其中。

最后我们可直接通过

func NewConfig(adapterName, filename string) (Configer, error)

函数来直接实例化一个对象。

然后直接使用这定义的接口中的方法。

首先看文件

选择同名文件config.go进入,可看到定义了一个接口

type Configer interface {Set(key, val string) error   //support section::key type in given key when using ini type.String(key string) string    //support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same.Strings(key string) []string //get string sliceInt(key string) (int, error)Int64(key string) (int64, error)Bool(key string) (bool, error)Float(key string) (float64, error)DefaultString(key string, defaultVal string) string      // support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same.DefaultStrings(key string, defaultVal []string) []string //get string sliceDefaultInt(key string, defaultVal int) intDefaultInt64(key string, defaultVal int64) int64DefaultBool(key string, defaultVal bool) boolDefaultFloat(key string, defaultVal float64) float64DIY(key string) (interface{}, error)GetSection(section string) (map[string]string, error)SaveConfigFile(filename string) error
 }
 

注册到其中的方法:其实就是维护一个map而已

看其他实现的结构,使用该函数注册到其中

ini的

 

json的

其他的也都不用看了,非常简单


标签:

上一篇: unity ugui 锚点与重心点 下一篇:
素材巴巴 Copyright © 2013-2021 http://www.sucaibaba.com/. Some Rights Reserved. 备案号:备案中。