成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go 云原生實(shí)戰(zhàn):如何增加應(yīng)用配置模塊

開(kāi)發(fā) 前端
本文介紹了項(xiàng)目配置文件的由來(lái)和重要性,并從零到一編寫代碼,成功在我們的 Web 項(xiàng)目中增加了應(yīng)用配置功能。并結(jié)合上一節(jié)的日志功能進(jìn)行了測(cè)試。

Part1介紹

當(dāng)我們?yōu)樽约壕帉懗绦驎r(shí),通常會(huì)將一些重要的配置項(xiàng)直接寫在源代碼里,比如:服務(wù)器監(jiān)聽(tīng)的端口、數(shù)據(jù)庫(kù)使用的名稱和端口號(hào)、HTTP請(qǐng)求超時(shí)的持續(xù)時(shí)間...

但是,如果我們嘗試將這個(gè)項(xiàng)目開(kāi)源分享給他人使用,用戶使用的數(shù)據(jù)庫(kù)的用戶名和名稱可能與你不相同,甚至你還要為他們的服務(wù)器使用另一個(gè)端口。

如果你還設(shè)置了數(shù)據(jù)庫(kù)的密碼的話,為了安全,更不可能在代碼中信息泄露出來(lái)。因此,本節(jié),將介紹如何增加我們的 ??sports?? 應(yīng)用的配置模塊。

Part2增加配置模塊

在許多的開(kāi)源項(xiàng)目中,配置都是通過(guò)鍵值(key-value) 數(shù)據(jù)結(jié)構(gòu)來(lái)處理的。在真實(shí)應(yīng)用中,你經(jīng)常會(huì)發(fā)現(xiàn)一個(gè)公開(kāi)配置選項(xiàng)的類(或者是結(jié)構(gòu)體),這個(gè)類經(jīng)常會(huì)將文件解析出來(lái),將每個(gè)選擇賦值。應(yīng)用程序通常會(huì)提出命令行選項(xiàng)以調(diào)整配置。

2.1 定義 Configuration 接口

接下來(lái),我們?yōu)閼?yīng)用程序增加配置的能力,這樣上面說(shuō)的很多配置就不用在代碼文件中定義。1、創(chuàng)建 ??sports/config??? 文件夾,然后新建一個(gè) ??config.go?? 文件,寫入如下的代碼:

package config

type Configuration interface {
GetString(name string) (configValue string, found bool)
GetInt(name string) (configValue int, found bool)
GetBool(name string) (configValue bool, found bool)
GetFloat(name string) (configValue float64, found bool)

GetStringDefault(name, defVal string) (configValue string)
GetIntDefault(name string, defVal int) (configValue int)
GetBoolDefault(name string, defVal bool) (configValue bool)
GetFloatDefault(name string, defVal float64) (configValue float64)

GetSection(sectionName string) (section Configuration, found bool)
}

可以看到,Configuration? 接口定義了檢索配置設(shè)置的方法,支持獲取字符串 string?、數(shù)字 int?、浮點(diǎn)型 float64?、布爾型 bool 的值:

  • GetString()
  • GetInt()
  • GetBool()
  • GetFloat()

還有一組方法允許提供一個(gè)默認(rèn)值:

  • GetStringDefault()
  • GetIntDefault()
  • GetBoolDefault()
  • GetFloatDefault()

配置數(shù)據(jù)將允許嵌套的配置部分,這個(gè)將使用 GetSection() 方法實(shí)現(xiàn)。

2.2 來(lái)看一個(gè)基本的 JSON 配置文件

配置可以從命令行中獲取,當(dāng)然更好的方式是將配置保存在一個(gè)文件中,由應(yīng)用程序自動(dòng)解析。

文件的格式取決于應(yīng)用程序的需求。如果你需要一個(gè)復(fù)雜的配置,有級(jí)別和層次(以 Windows 注冊(cè)表的方式)關(guān)系的話,那么你可能需要考慮 JSON、YAML 或 XML 等格式。

讓我們看一個(gè) JSON 配置文件的例子:

{
"server": {
"host": "localhost",
"port": 80
},
"database": {
"host": "localhost",
"username": "myUsername",
"password": "abcdefgh"
}
}

上面的 JSON 配置文件中定義了服務(wù)器 server 和數(shù)據(jù)庫(kù) database 的信息。但在本文中,我們基于上一節(jié)介紹的日志功能來(lái)看,為了簡(jiǎn)化操作,只簡(jiǎn)單配置我們的日志和主函數(shù)的信息。

2、在 sports? 目錄下,創(chuàng)建一個(gè) config.json 文件,寫入如下內(nèi)容:

{
"logging": {
"level": "debug"
},
"main": {
"message": "Hello, Let's Go! Hello from the config file"
}
}

這個(gè)配置文件定義了兩個(gè)配置部分,分別命名為 logging? 和 main:

  • logging? 部分包含一個(gè)單一的字符串配置設(shè)置,名稱為 level
  • main? 部分包含一個(gè)單一的字符串配置設(shè)置,名稱為 message

這個(gè)文件顯示了配置文件使用的基本結(jié)構(gòu),在 JSON 配置文件中,要注意引號(hào)和逗號(hào)符合 JSON 文件的格式要求,很多人經(jīng)常搞錯(cuò)。

2.3 實(shí)現(xiàn) Configuration 接口

為了能夠?qū)崿F(xiàn) Configuration? 接口,我們將在 sports/config? 文件夾下創(chuàng)建一個(gè) config_default.go 文件,然后寫入如下代碼:

package config

import "strings"

type DefaultConfig struct {
configData map[string]interface{}
}

func (c *DefaultConfig) get(name string) (result interface{}, found bool) {

data := c.configData
for _, key := range strings.Split(name, ":") {
result, found = data[key]
if newSection, ok := result.(map[string]interface{}); ok && found {
data = newSection
} else {
return
}
}
return
}

func (c *DefaultConfig) GetSection(name string) (section Configuration, found bool) {
value, found := c.get(name)
if found {
if sectionData, ok := value.(map[string]interface{}); ok {
section = &DefaultConfig{configData: sectionData}
}
}
return
}

func (c *DefaultConfig) GetString(name string) (result string, found bool) {
value, found := c.get(name)
if found {
result = value.(string)
}
return
}

func (c *DefaultConfig) GetInt(name string) (result int, found bool) {
value, found := c.get(name)
if found {
result = int(value.(float64))
}
return
}

func (c *DefaultConfig) GetBool(name string) (result bool, found bool) {
value, found := c.get(name)
if found {
result = value.(bool)
}
return
}

func (c *DefaultConfig) GetFloat(name string) (result float64, found bool) {
value, found := c.get(name)
if found {
result = value.(float64)
}
return
}

DefaultConfig? 結(jié)構(gòu)體用 map 實(shí)現(xiàn)了 Configuration 接口,嵌套配置部分也同樣用 maps 表示。即上面的代碼中的:

type DefaultConfig struct {
configData map[string] interface{}
}

一個(gè)單獨(dú)的配置可以通過(guò)將 section? 名稱和 setting? 名稱分開(kāi),例如:logging:level?,或者使用 map? 映射來(lái)根據(jù)鍵的名稱或者值,例如 logging 。

2.4 定義接收默認(rèn)值的方法

為了處理來(lái)自配置文件的值,我們?cè)?nbsp;sports/config? 文件夾下創(chuàng)建一個(gè) config_default_fallback.go 文件:

package config

func (c *DefaultConfig) GetStringDefault(name, val string) (result string) {
result, ok := c.GetString(name)
if !ok {
result = val
}
return
}

func (c *DefaultConfig) GetIntDefault(name string, val int) (result int) {
result, ok := c.GetInt(name)
if !ok {
result = val
}
return
}

func (c *DefaultConfig) GetBoolDefault(name string, val bool) (result bool) {
result, ok := c.GetBool(name)
if !ok {
result = val
}
return
}

func (c *DefaultConfig) GetFloatDefault(name string, val float64) (result float64) {
result, ok := c.GetFloat(name)
if !ok {
result = val
}
return
}

2.5 定義從配置文件加載數(shù)據(jù)的函數(shù)

在 sports/config? 文件夾下新建一個(gè)加載 JSON 數(shù)據(jù)的 config_json.go 文件,寫入如下代碼:

package config

import (
"encoding/json"
"os"
"strings"
)

func Load(filename string) (config Configuration, err error) {
var data []byte
data, err = os.ReadFile(filename)
if err == nil {
decoder := json.NewDecoder(strings.NewReader(string(data)))
m := map[string]interface{}{}
err = decoder.Decode(&m)
if err == nil {
config = &DefaultConfig{configData: m}
}
}
return
}

Load? 函數(shù)讀取一個(gè)文件的內(nèi)容,將其包含的 JSON? 文件解析為一個(gè)映射,并使用該映射創(chuàng)建一個(gè) DefaultConfig 的值。

關(guān)于 Go 如何處理 JSON 文件,感興趣可以搜索我之前的文章:《Go 語(yǔ)言入門很簡(jiǎn)單:Go 語(yǔ)言解析JSON》

Part3使用 Configuration 配置系統(tǒng)

為了從剛剛增加的配置系統(tǒng)中獲取日志級(jí)別的信息,我們將回到上一節(jié)中 logging 文件夾中的 default_create.go 文件中,寫入如下代碼:

package logging

import (
"log"
"os"
"strings"

"sports/config"
)

// func NewDefaultLogger(level LogLevel) Logger {
func NewDefaultLogger(cfg config.Configuration) Logger {

// 使用 Configuration
var level LogLevel = Debug
if configLevelString, found := cfg.GetString("logging:level"); found {
level = LogLevelFromString(configLevelString)
}

flags := log.Lmsgprefix | log.Ltime
return &DefaultLogger{
minLevel: level,
loggers: map[LogLevel]*log.Logger{
Trace: log.New(os.Stdout, "TRACE ", flags),
Debug: log.New(os.Stdout, "DEBUG ", flags),
Information: log.New(os.Stdout, "INFO ", flags),
Warning: log.New(os.Stdout, "WARNING ", flags),
Fatal: log.New(os.Stdout, "FATAL ", flags),
},
triggerPanic: true,
}
}

func LogLevelFromString(val string) (level LogLevel) {
switch strings.ToLower(val) {
case "debug":
level = Debug
case "information":
level = Information
case "warning":
level = Warning
case "fatal":
level = Fatal
case "none":
level = None
}
return
}

在 JSON 中沒(méi)有很好的方法來(lái)表示 iota? 值,所以我們使用一個(gè)字符串并定義了 LogLevelFromString()? 函數(shù),以此來(lái)將配置設(shè)置轉(zhuǎn)換為 LogLevel 的值。

最后,我們更新 main()? 函數(shù)來(lái)加載和應(yīng)用配置數(shù)據(jù),并使用配置系統(tǒng)來(lái)讀取它所輸出的信息,更改 main.go 文件如下。

package main

import (
// "fmt"
"sports/config"
"sports/logging"
)

// func writeMessage(logger logging.Logger) {
// // fmt.Println("Let's Go")
// logger.Info("Let's Go, logger")
// }

// func main() {

// var logger logging.Logger = logging.NewDefaultLogger(logging.Information)
// writeMessage(logger)
// }

func writeMessage(logger logging.Logger, cfg config.Configuration) {
section, ok := cfg.GetSection("main")
if ok {
message, ok := section.GetString("message")
if ok {
logger.Info(message)
} else {
logger.Panic("Cannot find configuration setting")
}
} else {
logger.Panic("Config section not found")
}
}

func main() {

var cfg config.Configuration
var err error
cfg, err = config.Load("config.json")
if err != nil {
panic(err)
}

var logger logging.Logger = logging.NewDefaultLogger(cfg)
writeMessage(logger, cfg)
}

至此,我們的配置是從 config.json? 文件中獲取,通過(guò) NewDefaultLogger() 函數(shù)來(lái)傳遞 Configuration 的實(shí)現(xiàn),最終讀取到 log 日志級(jí)別設(shè)置。

writeMessage() 函數(shù)顯示了配置部分的使用,提供了組件所需的設(shè)置,特別是在需要多個(gè)具有不同配置的實(shí)例時(shí),每一個(gè)設(shè)置都可以在自己的部分進(jìn)行定義。

最后的項(xiàng)目結(jié)構(gòu)如圖:

圖片

最終,我們?cè)诮K端中編譯并運(yùn)行我們整個(gè)代碼:

$ go run .
17:20:46 INFO Hello, Let's Go! Hello from the config file

整個(gè)代碼會(huì)輸出并打印出配置文件中的信息,如圖所示:

圖片

Part4總結(jié)

本文介紹了項(xiàng)目配置文件的由來(lái)和重要性,并從零到一編寫代碼,成功在我們的 Web 項(xiàng)目中增加了應(yīng)用配置功能。并結(jié)合上一節(jié)的日志功能進(jìn)行了測(cè)試。

其實(shí)在 Go 開(kāi)源項(xiàng)目中,有個(gè)非常著名的開(kāi)源配置包:Viper ,提供針對(duì) Go 應(yīng)用項(xiàng)目的完整配置解決方案,幫助我們快速處理所有類型的配置需求和配置文件格式。目前 GitHub Stars 數(shù)量高達(dá) 21k,今后將在后續(xù)的文章中介紹這個(gè)項(xiàng)目。

責(zé)任編輯:武曉燕 來(lái)源: 宇宙之一粟
相關(guān)推薦

2020-12-01 17:44:15

華為云Go語(yǔ)言云原生

2022-02-21 09:00:00

云原生應(yīng)用開(kāi)發(fā)

2022-10-27 18:03:04

GogRPC云原生

2023-12-26 10:04:29

Electron應(yīng)用開(kāi)發(fā)框架

2017-12-10 14:13:14

云服務(wù)云原生應(yīng)用程序

2021-10-11 09:00:00

云原生Kubernetes安全

2020-07-16 08:05:15

JavaGo

2025-06-04 10:08:00

Go開(kāi)發(fā)云原生

2021-07-20 09:44:34

云原生應(yīng)用程序安全云安全

2020-10-21 10:04:56

云原生應(yīng)用架構(gòu)

2023-05-15 08:01:21

k8s容器

2025-07-03 11:21:04

2022-06-22 09:24:30

云原生Go 語(yǔ)言

2021-10-29 10:12:34

云原生勒索軟件網(wǎng)絡(luò)攻擊

2023-03-27 07:43:35

2022-08-24 16:47:01

云原生安全通信

2024-05-13 08:00:00

2022-05-06 09:40:48

智能云原生云原生人工智能

2019-08-07 17:18:18

云計(jì)算云原生函數(shù)

2020-01-03 14:03:46

云計(jì)算開(kāi)發(fā)云原生
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 欧美日韩在线一区二区三区 | 波多野结衣中文字幕一区二区三区 | 久久国际精品 | 亚洲精品在线视频 | 51ⅴ精品国产91久久久久久 | 国产91视频一区二区 | 毛片av免费在线观看 | 久久免费精品 | 国产一区影院 | 一区二区三区四区国产 | 亚洲精品影院 | 免费黄色录像片 | 99精品一区二区 | 色偷偷888欧美精品久久久 | 国产一级在线观看 | 青青久视频| 国产十日韩十欧美 | 亚洲成人高清 | 国产精品不卡一区 | 国产精品一区二区免费看 | 日韩不卡一区二区 | 日本在线视频一区二区 | 欧美福利精品 | 日日综合 | 成年人黄色小视频 | 亚洲精品成人av久久 | 中文字幕在线视频精品 | 91精品国产乱码久久久久久久久 | 亚洲性爰| 中文字幕一区二区三区四区五区 | 日韩av在线一区二区 | 国产视频精品视频 | 欧美午夜在线 | 精品国产一区二区三区免费 | 精品一二区| 午夜影院视频在线观看 | 日韩视频在线一区二区 | 亚洲精品大全 | aa级毛片毛片免费观看久 | 免费国产视频 | 亚洲美女视频 |