golang单例模式加载服务配置

golang中单例模式体现在很多地方, 比如init函数,当包被导入的时候只会被执行一次。实现单例模式有很多种方式,这里给出几种简单的实现:

互斥锁

对全局共享变量加锁,如果该变量不是nil,那么证明已经被创建了实例,直接返回它的值就好。

type singleton struct {
    
    }

var (
	ins *singleton
	mu sync.Mutex
)

func Instance() *singleton {
    
    
	mu.Lock()
	defer mu.Unlock()

	if ins == nil {
    
    
		ins = &singleton{
    
    }
	}

	return ins
}

互斥锁 + 原子操作

加互斥锁是比较耗时的,我们可以使用一个变量来标识是否已经被实例化,维护该变量只需要go中原生支持的原子操作:atomic。

var (
	ins *singleton
	mu sync.Mutex
	created uint32
)

func Instance2() *singleton {
    
    
	if atomic.LoadUint32(&created) == 1 {
    
    
		return ins
	}

	mu.Lock()
	defer mu.Unlock()

	if ins == nil {
    
    
		ins = &singleton{
    
    }
		atomic.StoreUint32(&created, 1)
	}

	return ins
}

Once

通过atomic+mutex的方式实现单例模式,其实就是go中Once的实现方式。

var (
	ins *singleton
	once sync.Once
)

func Instance3() *singleton {
    
    
	once.Do(func() {
    
    
		ins =  &singleton{
    
    }
	})

	return ins
}

实战-单例模式加载服务配置文件

.env文件如下

DEBUG=true

POSTGRESQL_SERVER_HOST=172.20.1.24
POSTGRESQL_SERVER_PORT=43007
POSTGRESQL_SERVER_EDGEDB_USER=postgres
POSTGRESQL_SERVER_EDGEDB_PASS=xxxxxxx
POSTGRESQL_SERVER_POOLSIZE=10

RABBITMQ_SERVER_HOST=172.20.1.24
RABBITMQ_SERVER_PORT=43008
RABBITMQ_SERVER_USER=rabbitmq
RABBITMQ_SERVER_PASS=xxxxxx
RABBITMQ_SERVER_VHOST=/

服务里定义了Config结构体,需要从.env文件加载到config实例

package main

import (
	"errors"
	"fmt"
	"github.com/caarlos0/env/v6"
	"github.com/go-playground/validator/v10"
	"os"
	"sync"

	"github.com/joho/godotenv"
)

type Config struct {
    
    
	Postgresql struct {
    
    
		Host       string `yaml:"host" env:"POSTGRESQL_SERVER_HOST" envDefault:"postgresql"`
		Port       int    `yaml:"port" env:"POSTGRESQL_SERVER_PORT" envDefault:"5432"`
		EdgedbUser string `yaml:"user" env:"POSTGRESQL_SERVER_EDGEDB_USER" envDefault:"postgres"`
		EdgedbPass string `yaml:"pass" env:"POSTGRESQL_SERVER_EDGEDB_PASS" envDefault:"password"`
		EdgedbName string `yaml:"name" env:"POSTGRESQL_SERVER_EDGEDB_NAME" envDefault:"edgedb"`
		PoolSize   int    `yaml:"pool_size" env:"POSTGRESQL_SERVER_POOLSIZE" envDefault:"500"` // 设置连接池的最大连接数
	}

	Rabbitmq struct {
    
    
		Host  string `env:"RABBITMQ_SERVER_HOST" envDefault:"rabbitmq"`
		Port  int64  `env:"RABBITMQ_SERVER_PORT" envDefault:"5672"`
		User  string `env:"RABBITMQ_SERVER_USER" envDefault:"rabbitmq"`
		Pass  string `env:"RABBITMQ_SERVER_PASS" envDefault:"EdgeCore2018"`
		Vhost string `env:"RABBITMQ_SERVER_VHOST" envDefault:"/"`
	}

	Log struct {
    
    
		DEBUG            bool   `yanl:"debug" env:"DEBUG"` // 如果配置true, 则ConsoleLevel/FileLevel="debug"
		Path             string `yaml:"path" env:"LOG_PATH" envDefault:"./logs"`
		MaxAge           int    `yaml:"max_age" env:"LOG_MAX_AGE" envDefault:"30"`         // unit: day
		MaxSize          int    `yaml:"max_size" env:"LOG_MAX_SIZE" envDefault:"100"`      // unit: M (MillionBytes)
		MaxBackups       int    `yaml:"max_backups" env:"LOG_MAX_BACKUPS" envDefault:"30"` // unit: files number
		ConsoleLevel     string `yaml:"console_level" env:"LOG_CONSOLE_LEVEL" envDefault:"error"`
		ConsoleFormat    string `yaml:"console_format" env:"LOG_CONSOLE_FORMAT" envDefault:"str"` //ex: 'str'/'json'
		FileLevel        string `yaml:"level" env:"LOG_FILE_LEVEL" envDefault:"info"`
		FileFormat       string `yaml:"file_format" env:"LOG_FILE_FORMAT" envDefault:"json"` //ex: 'str'/'json'
		LogPushIsEnabled string `yaml:"log_push_rabbitmq_isenabled" env:"LOG_PUSH_RABBITMQ_ISENABLED" envDefault:"true"`
		LogPushLevel     string `yaml:"log_push_rabbitmq_level" env:"LOG_PUSH_RABBITMQ_LEVEL" envDefault:"info"`
	}
}

var (
	cfg  *Config
	err  error
	once sync.Once
)

// LoadConfig Load global configs
func LoadConfig(args ...string) (*Config, error) {
    
    
	// 单例
	once.Do(
		func() {
    
    
			var envFile = ".env"
			cfg = new(Config)

			if len(args) != 0 {
    
    
				envFile = args[0]
			}

			// loads .env file to inner ENV
			if _, err = os.Stat(envFile); err == nil {
    
    
				// file exists
				if err = godotenv.Load(envFile); err != nil {
    
    
					return
				}
			} else if errors.Is(err, os.ErrNotExist) {
    
    
				// file does not exist, use ENV
			} else {
    
    
				return
			}

			// loads inner ENV into a Config object (cfg)
			if err = env.Parse(cfg); err != nil {
    
    
				return
			}

			// check cfg object
			if err = validator.New().Struct(cfg); err != nil {
    
    
				return
			}

			// Make DEBUG work if setup
			if cfg.Log.DEBUG == true {
    
    
				cfg.Log.ConsoleLevel = "debug"
				cfg.Log.FileLevel = "debug"
			}
		},
	)

	return cfg, err
}

func main() {
    
    
	if cfg, err := LoadConfig(); err != nil {
    
    
		fmt.Println("加载配置失败")
	} else {
    
    
		fmt.Println("加载配置成功, config: ", cfg)
	}
}

结果打印:

加载配置成功, config:  &{
    
    {
    
    172.20.1.24 43007 postgres xxxxxxx edgedb 10} {
    
    172.20.1.24 43008 rabbitmq xxxxxx /} {
    
    true ./logs 30 100 30 debug str debug json true info}}

猜你喜欢

转载自blog.csdn.net/qq_38923792/article/details/128147803