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

ITCloud · 2019-09-07 16:16:46 · 2876 次点击 · 预计阅读时间 5 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2019-09-07 16:16:46 的文章,其中的信息可能已经有所发展或是发生改变。

项目地址: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的时候可以直接组合该结构体,像下面这样,这样你就不需要去实现所有的方法了
type MyStarter struct {
  infra.BaseStarter
}
  1. 定义结构体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使用

$ go get github.com/anypick/infra

1. 自定义Starter

具体代码请参照github源码:infra-gin

这里以整合Gin框架为例,关键点:

【gin.go】

  1. 组合BaseStarter
type GinStarter struct {
    infra.BaseStarter
}
  1. 对外暴露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】

这是一个Controller,需要实现接口

// 用于业务的代码的注入,例如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()
}

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

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

2876 次点击  
加入收藏 微博
2 回复  |  直到 2019-09-09 18:02:51
ITCloud
ITCloud · #1 · 6年之前

好用呀

ITCloud
ITCloud · #2 · 6年之前

没人看吗

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