一、为什么要使用全局Starter
使用Golang作为项目开发时经常会需要在程序中进行硬编码的框架配置,譬如iris的启动端口号、mysql的连接ip及链接参数协议、日志框架的配置等等。
使用硬编码配置会出现配置更换不便和管理不便的问题,并且代码会十分冗杂。
所以可以使用类似于Java SpringBoot的全局统一配置(application.properties)和Starter的开发模式,把配置都定义在配置文件中,不同的框架配置代码通过不同的Starter来进行管理。
使用到的技术:
- go mod(版本管理)
- 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]")
}