infra一个golang实现的简单易用的‘依赖’注入框架

ITCloud · · 2662 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

### 项目地址:[infra](https://github.com/anypick/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】** > 1. 定义接口`typ Starter interface{...}`,所有的自定义的Starter都要实现这个接口,这里已经有一个自定义实现了`type BaseStarter struct{}`,当你定义一个属于自己的Starter的时候可以直接组合该结构体,像下面这样,这样你就不需要去实现所有的方法了 > > ```go > type MyStarter struct { > infra.BaseStarter > } > ``` > > 2. 定义结构体`type starterRegister struct{...}`,用于存储你自定义的`Starter`,这些Starter有的是阻塞的(如`Gin`,`Grpc`),阻塞启动优先级要比非阻塞优先级低,当有多个阻塞Starter,只有最后一个可以阻塞整个程序,其他的应该使用协程去运行。 **【boot.go】** > 1. 定义结构体`type BootApplication struct{...}`,对于`Starter`的启动,需要经历`Init`,` Start`,` Setup`三个阶段,所以这里使用了`模板设计模式` **【initializer.go】** > 1. 定义接口`type Initializer interface {...}`,对于业务代码中实例(例如Controller层),不希望使用`typ Starter interface{...}`这个接口,我们可以实现这个接口。这里还有`type InitializerRegister struct{}`结构体,用于存储业务代码中实例。 > 2. `type BaseInitializerStarter struct{}` 这是一个`Starter`,负责统一调用业务实例 **【utils/】**:定义一些工具类。 **【base/】**:定义`YamlStarter` > 对于这个YamlStarter使用`装饰者设计模式`支持用户扩展自定义配置。 # 3. infra使用 ```shell $ go get github.com/anypick/infra ``` ## 1. 自定义Starter 具体代码请参照github源码:[infra-gin](https://github.com/anypick/infra-gin) > 这里以整合Gin框架为例,关键点: > > **【gin.go】** > > 1. 组合`BaseStarter` > > ```go > type GinStarter struct { > infra.BaseStarter > } > ``` > > 2. 对外暴露gin实例(单例) > > ```go > var ginEngine *gin.Engine > > // 对外暴露 > func Gin() *gin.Engine { > return ginEngine > } > ``` ## 2. 自定义Starter 具体代码参照github源码:[infra-logrus](https://github.com/anypick/infra-logrus) 这个自定义Stater整合logrus框架为例 **【logrus.go】** > 和`gin.go`一样,目的都是组合`infra.BaseStarter`实现`Starter接口` 这里主要关注点:**【logrus_config.go】** 定义一个配置log的配置结构体,`Prefix`,为必须字段,主要作用是用来获取改结构体。这个结构体实现了infra项目中`type YamlConfig interface{}`接口(在目录base/props/container/下)。 ```go // 日志配置 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`中 ```go func init() { container.RegisterYamContainer(&LogConfig{Prefix: YamlPrefix}) } ``` # 4.整合 项目地址:[infra-example](https://github.com/anypick/infra-example) ```shell $ 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】** ```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】** > 这是一个Controller,需要实现接口 > > ```go > // 用于业务的代码的注入,例如Dao层,Service层,Controller层 > type Initializer interface { > Init() > } > ``` **【main.go】** > GinExample.go中有一个init函数,需要在这里引入 ```go 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() } ```

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2662 次点击  
加入收藏 微博
2 回复  |  直到 2019-09-09 18:02:51
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传