infra一个golang实现的简单易用的‘依赖’注入框架
项目地址: infra
1. infra功能介绍
infra是一个Golang实现的极其简单的依赖注入框架,使用Yaml作为配置文件。支持 组件配置
, 组件扩展
目前支持的组件
Gin:https://github.com/anypick/infra-gin
Logrus:https://github.com/anypick/infra-logrus
MySQL:https://github.com/anypick/infra-mysql
Redis:https://github.com/anypick/infra-redis
RabbitMQ:https://github.com/anypick/infra-rabbit
GRPC:开发中
2. infra文件介绍
【starter.go】
-
定义接口
typ Starter interface{...}
,所有的自定义的Starter都要实现这个接口,这里已经有一个自定义实现了type BaseStarter struct{}
,当你定义一个属于自己的Starter的时候可以直接组合该结构体,像下面这样,这样你就不需要去实现所有的方法了
type MyStarter struct { infra.BaseStarter }
-
定义结构体
type starterRegister struct{...}
,用于存储你自定义的Starter
,这些Starter有的是阻塞的(如Gin
,Grpc
),阻塞启动优先级要比非阻塞优先级低,当有多个阻塞Starter,只有最后一个可以阻塞整个程序,其他的应该使用协程去运行。
【boot.go】
-
定义结构体
type BootApplication struct{...}
,对于Starter
的启动,需要经历Init
,Start
,Setup
三个阶段,所以这里使用了模板设计模式
【initializer.go】
-
定义接口
type Initializer interface {...}
,对于业务代码中实例(例如Controller层),不希望使用typ Starter interface{...}
这个接口,我们可以实现这个接口。这里还有type InitializerRegister struct{}
结构体,用于存储业务代码中实例。 -
type BaseInitializerStarter struct{}
这是一个Starter
,负责统一调用业务实例
【utils/】:定义一些工具类。
【base/】:定义 YamlStarter
对于这个YamlStarter使用 装饰者设计模式
支持用户扩展自定义配置。
3. infra使用
$ go get github.com/anypick/infra
1. 自定义Starter
具体代码请参照github源码: infra-gin
【gin.go】
-
组合
BaseStarter
type GinStarter struct { infra.BaseStarter }
- 对外暴露gin实例(单例)
var ginEngine *gin.Engine // 对外暴露 func Gin() *gin.Engine { return ginEngine }
2. 自定义Starter
具体代码参照github源码: infra-logrus
这个自定义Stater整合logrus框架为例
【logrus.go】
和 gin.go
一样,目的都是组合 infra.BaseStarter
实现 Starter接口
这里主要关注点: 【logrus_config.go】
定义一个配置log的配置结构体, Prefix
,为必须字段,主要作用是用来获取改结构体。这个结构体实现了infra项目中 type YamlConfig interface{}
接口(在目录base/props/container/下)。
// 日志配置 type LogConfig struct { Prefix string Level string `yaml:"level"` LogFileName string `yaml:"logFileName"` FilePath string `yaml:"filePath"` MaxAge int `yaml:"maxAge"` RotationTime int `yaml:"rotationTime"` } func (l *LogConfig) ConfigAdd(config map[interface{}]interface{}) { l.Level = fmt.Sprintf("%v", config["level"]) l.LogFileName = fmt.Sprintf("%v", config["logFileName"]) l.FilePath = fmt.Sprintf("%v", config["filePath"]) l.MaxAge = config["maxAge"].(int) l.RotationTime = config["rotationTime"].(int) }
使用init方法,将该结构体放入 YamlContainer
中
func init() { container.RegisterYamContainer(&LogConfig{Prefix: YamlPrefix}) }
4.整合
项目地址: infra-example
$ go get github.com/anypick/infra $ go get github.com/anypick/infra-logrus $ go get github.com/anypick/infra-gin
前面我们已经定义好了两个starter,现在来新建一个项目 infra-example
,对于项目的目录我喜欢这样:
├── README.md ├── app.go ├── brun │ └── main.go ├── go.mod ├── go.sum ├── resources │ └── application.yml └── src └── GinExample.go
application.yml
:为配置文件目录
main.go
:程序启动类
app.go
:负责注册需要的实例
src
:定义业务代码
【app.go】
package example import ( "github.com/anypick/infra" "github.com/anypick/infra-gin" "github.com/anypick/infra-logrus" "github.com/anypick/infra/base/props/container" ) func init() { // YamlStarter,是必须要注册的Starter infra.Register(&container.YamlStarter{}) infra.Register(&baselog.LogrusStarter{}) infra.Register(&basegin.GinStarter{}) // BaseInitializerStarter也是必须要注册的Starter infra.Register(&infra.BaseInitializerStarter{}) }
【GinExample.go】
// 用于业务的代码的注入,例如Dao层,Service层,Controller层 type Initializer interface { Init() }
【main.go】
GinExample.go中有一个init函数,需要在这里引入
import ( // 引入app.go init函数 _ "example" // 引入GinExample.go init函数 _ "example/src" "flag" "fmt" "github.com/anypick/infra" "github.com/anypick/infra/base/props" "github.com/anypick/infra/utils/common" ) func main() { // 生成网站:http://patorjk.com/software/taag banner := `...` fmt.Println(banner) profile := flag.String("profile", "", "环境信息") flag.Parse() resource := "" if common.StrIsBlank(*profile) { resource = "resources/application.yml" } else { resource = fmt.Sprintf("resources/application-%s.yml", *profile) } yamlConf := props.NewYamlSource(resource) application := infra.New(*yamlConf) application.Start() }