1. Why use global Starter

When working with Golang as a project, you often need to hard-code framework configurations in your program, such as the startup port number for IRIS, the connection IP and link parameter protocol for mysql, the configuration of the logging framework, and so on.

Hard-coded configurations can be difficult to replace and manage, and the code can be jumbled.

Therefore, you can use the global unified configuration (Application.properties) and Starter development mode similar to Java SpringBoot, and the configuration is defined in the configuration file, different framework configuration code is managed by different Starter.

Techniques used:

  1. Go Mod (version management)
  2. Viper (Configuration Management)

Second, global Starter code implementation

2.1 Scaffold project structure

2.2 Specific code

  • main/main.go
package main

import (
	"github.com/spf13/viper"
	"golang-starter-project/src/infra"
	// Triggers the global init function
	_ "golang-starter-project/src"
)

// Global Starter to configure the Starter and start the project
func main(a) {
	// Get the global configuration file
	conf := getConfig()
	app := infra.NewBootApplication(conf)
	app.Run()
	select{}}func getConfig(a) *viper.Viper {
	conf := viper.New()
	conf.SetConfigName("config")
	conf.SetConfigType("yaml")
	conf.AddConfigPath("./src/main/")
	err := conf.ReadInConfig()
	iferr ! =nil {
		panic(err)
	}
	return conf
}
Copy the code
  • main/config.yaml
server:
  name: golang-starter-demo
  port: 8804
  enable: true
Copy the code
  • src/app.go
package src

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

// Preload all Starter containers
func init(a) {
	infra.Register(&starters.LogStarter{})
}
Copy the code
  • infra/starter.go
package infra

import "github.com/spf13/viper"

// The Starter interface, which defines the basic Starter methods
type Starter interface {
	// Initialize the Starter configuration
	Init(conf *viper.Viper)
	// Configure the Starter parameters
	Setup(conf *viper.Viper)
	/ / start the Starter
	Start(conf *viper.Viper)
}

// BaseStarter, default empty implementation of the Starter interface
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) {}

// The Starter registry, which holds all Starter instances, global singletons
type starterRegister struct {
	starters []Starter
}

var register = new(starterRegister)

/ / get starterRegister
func StarterRegister(a) *starterRegister {
	return register
}

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

// Obtain all registered Starters
func (s *starterRegister) allStarters(a) []Starter {
	return s.starters
}

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

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

import "github.com/spf13/viper"

// Global Starter configuration and initiators, global singleton
type bootApplication struct {
	conf *viper.Viper
}

var conf *viper.Viper

// Pass in the global configuration file conf and get bootApplication
func NewBootApplication(vipConf *viper.Viper) *bootApplication {
	if vipConf == nil {
		panic("conf is nil")
	}
	conf = vipConf
	application := &bootApplication{conf: vipConf}
	return application
}

// Get the global configuration file
func Conf(a) *viper.Viper {
	if conf == nil {
		panic("conf is nil")}return conf
}

// Start the bootApplication and initialize the Starter
func (b *bootApplication) Run(a) {
	/ / initialization
	initStarters()
	/ / configuration
	setupStarters()
	/ / start
	startStarters()
}

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

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

func initStarters(a) {
	for _, s := range AllStarters() {
		s.Init(conf)
	}
}
Copy the code
  • 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"
)

/ / implementation BaseStarter
type LogStarter struct {
	infra.BaseStarter
}

func (l *LogStarter) Setup(conf *viper.Viper) {
	// Define the log format
	formatter := &prefixed.TextFormatter{}
	// Enable full timestamp output and timestamp format
	formatter.FullTimestamp = true
	formatter.TimestampFormat = "The 2006-01-02. 15:04:05. 000000"
	// The console is highlighted
	formatter.ForceFormatting = true
	formatter.ForceColors = true
	formatter.DisableColors = false
	// Set the color style for the highlight
	formatter.SetColorScheme(&prefixed.ColorScheme{
		InfoLevelStyle:  "green",
		WarnLevelStyle:  "yellow",
		ErrorLevelStyle: "red",
		FatalLevelStyle: "41",
		PanicLevelStyle: "41",
		DebugLevelStyle: "blue",
		PrefixStyle:     "cyan",
		TimestampStyle:  "37",
	})
	logrus.SetFormatter(formatter)
	// The log level is set by the environment variable
	// You can change it to the configuration later
	level := os.Getenv("log.debug")
	if level == "true" {
		logrus.SetLevel(logrus.DebugLevel)
	}

	logrus.Info("Test log starter [1]")
	logrus.Debug("Test log starter [2]")}Copy the code

Three, the realization of logical sequence diagram

Github address

Github.com/pbrong/gola…