Golang-使用Starter模式来实现项目全局配置初始化

1,225 阅读2分钟

一、为什么要使用全局Starter

使用Golang作为项目开发时经常会需要在程序中进行硬编码的框架配置,譬如iris的启动端口号、mysql的连接ip及链接参数协议、日志框架的配置等等。

使用硬编码配置会出现配置更换不便和管理不便的问题,并且代码会十分冗杂。

所以可以使用类似于Java SpringBoot的全局统一配置(application.properties)和Starter的开发模式,把配置都定义在配置文件中,不同的框架配置代码通过不同的Starter来进行管理。

使用到的技术:

  1. go mod(版本管理)
  2. viper(配置管理)

二、全局Starter的代码实现

2.1、脚手架项目结构

在这里插入图片描述

2.2、具体代码

  • main/main.go
package main

import (
	"github.com/spf13/viper"
	"golang-starter-project/src/infra"
	// 触发全局init函数
	_ "golang-starter-project/src"
)

// 全局Starter启动器,对Starter进行配置并启动项目
func main() {
	// 获取全局配置文件
	conf := getConfig()
	app := infra.NewBootApplication(conf)
	app.Run()
	select {}
}

func getConfig() *viper.Viper {
	conf := viper.New()
	conf.SetConfigName("config")
	conf.SetConfigType("yaml")
	conf.AddConfigPath("./src/main/")
	err := conf.ReadInConfig()
	if err != nil {
		panic(err)
	}
	return conf
}
  • main/config.yaml
server:
  name: golang-starter-demo
  port: 8804
  enable: true
  • src/app.go
package src

import (
	"golang-starter-project/src/infra"
	"golang-starter-project/src/infra/starters"
)

// 将所有Starter预先载入启动容器
func init() {
	infra.Register(&starters.LogStarter{})
}
  • infra/starter.go
package infra

import "github.com/spf13/viper"

// Starter接口,定义Starter基本方法
type Starter interface {
	// 初始化Starter配置
	Init(conf *viper.Viper)
	// 配置Starter参数
	Setup(conf *viper.Viper)
	// 启动Starter
	Start(conf *viper.Viper)
}

// BaseStarter,Starter接口的默认空实现
var _ Starter = new(BaseStarter)

type BaseStarter struct{}

func (b *BaseStarter) Init(conf *viper.Viper)  {}
func (b *BaseStarter) Setup(conf *viper.Viper) {}
func (b *BaseStarter) Start(conf *viper.Viper) {}

// Starter的注册器,保存所有Starter实例,全局单例
type starterRegister struct {
	starters []Starter
}

var register = new(starterRegister)

// 获取starterRegister
func StarterRegister() *starterRegister {
	return register
}

// 注册Starter
func (s *starterRegister) register(starter Starter) {
	s.starters = append(s.starters, starter)
}

// 获取所有被注册的Starters
func (s *starterRegister) allStarters() []Starter {
	return s.starters
}

func Register(starter Starter) {
	register.register(starter)
}

func AllStarters() []Starter {
	return register.allStarters()
}
  • infra/boot.go
package infra

import "github.com/spf13/viper"

// 全局Starter配置及启动器,全局单例
type bootApplication struct {
	conf *viper.Viper
}

var conf *viper.Viper

// 传入全局配置文件conf,并获取bootApplication
func NewBootApplication(vipConf *viper.Viper) *bootApplication {
	if vipConf == nil {
		panic("conf is nil")
	}
	conf = vipConf
	application := &bootApplication{conf: vipConf}
	return application
}

// 获取全局配置文件
func Conf() *viper.Viper {
	if conf == nil {
		panic("conf is nil")
	}
	return conf
}

// 启动bootApplication,初始化Starter并启动
func (b *bootApplication) Run() {
	// 初始化
	initStarters()
	// 配置
	setupStarters()
	// 启动
	startStarters()
}

func startStarters() {
	for _, s := range AllStarters() {
		s.Start(conf)
	}
}

func setupStarters() {
	for _, s := range AllStarters() {
		s.Setup(conf)
	}
}

func initStarters() {
	for _, s := range AllStarters() {
		s.Init(conf)
	}
}
  • starters/logrus_starter.go
package starters

import (
	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	prefixed "github.com/x-cray/logrus-prefixed-formatter"
	"golang-starter-project/src/infra"
	"os"
)

// 实现BaseStarter
type LogStarter struct {
	infra.BaseStarter
}

func (l *LogStarter) Setup(conf *viper.Viper) {
	// 定义日志格式
	formatter := &prefixed.TextFormatter{}
	//开启完整时间戳输出和时间戳格式
	formatter.FullTimestamp = true
	formatter.TimestampFormat = "2006-01-02.15:04:05.000000"
	// 控制台高亮显示
	formatter.ForceFormatting = true
	formatter.ForceColors = true
	formatter.DisableColors = false
	//设置高亮显示的色彩样式
	formatter.SetColorScheme(&prefixed.ColorScheme{
		InfoLevelStyle:  "green",
		WarnLevelStyle:  "yellow",
		ErrorLevelStyle: "red",
		FatalLevelStyle: "41",
		PanicLevelStyle: "41",
		DebugLevelStyle: "blue",
		PrefixStyle:     "cyan",
		TimestampStyle:  "37",
	})
	logrus.SetFormatter(formatter)
	//日志级别,通过环境变量来设置
	// 后期可以变更到配置中来设置
	level := os.Getenv("log.debug")
	if level == "true" {
		logrus.SetLevel(logrus.DebugLevel)
	}

	logrus.Info("测试log starter [1]")
	logrus.Debug("测试log starter [2]")
}

三、实现逻辑时序图

在这里插入图片描述

四、Github地址

github.com/pbrong/gola…