Golang实现依赖注入+gin

Author Avatar
Yangzzz 7月 05, 2020
722字 | 3分 |
  • 在其它设备中阅读本文章

Go实现依赖注入

最近在使用go开发的时候,发现构建系统依赖树非常繁琐,需要手动去new很多对象,又手工代码将它们拼接起来,写了一堆非常冗繁的代码。之前在laravel的使用中有其强大的ioc,都没有这方面的困扰。就在想golang中有没有好用的依赖注入方案,查询资料,发现了facebook团队开源的inject。GitHub地址:http://github.com/facebookgo/inject

没有依赖注入的系统:

在代码上的表现:

func NewUserRepository() UserRepositoryImp {
    return &UserManagerRepository{
        Db: models.MysqlHandler,
    }
}

func NewUserServices(repository repositories.UserRepositoryImp) UserServiceImp {
    return &UserService{repository}
}

func NewUserController(userServices services.UserServiceImp) UserImp {
    return &UserController{UserServices: userServices}
}

repository := repositories.NewUserRepository()
userServices := services.NewUserServices(repository)
controller := controllers.NewUserController(userServices)

这里也能看出口想当的难受。而且重复代码很多。

使用的依赖

go get github.com/facebookgo/inject

简单的使用例子

type DBEngine struct {
    Name string
}

type UserDB struct {
    Db *DBEngine `inject:""`
}

type UserService struct {
    Db *UserDB `inject:""`
}

type App struct {
    Name string
    User *UserService `inject:""`
}

func (a *App) Create() string {
    return "create app, in db name:" + a.User.Db.Db.Name + " app name :" + a.Name
}

type Object struct {
    App *App
}

func Init() *Object {
    var g inject.Graph

    // 不适用依赖注入
    //a := DBEngine{Name: "db1"}
    //b := UserDB{&a}
    //c := UserService{&b}
    //app := App{Name: "go-app", User: &c}

    app := App{Name: "go-app"}

    _ = g.Provide(
        &inject.Object{Value: &DBEngine{Name: "db1"}},
        &inject.Object{Value: &app},
    )
    _ = g.Populate()

    return &Object{
        App: &app,
    }

}
func TestMains(t *testing.T) {
    obj := Init()
    fmt.Println(obj.App.Create())
}

这样很简单就实现了golang的依赖注入,看这个开源库的源码发现,整个类库的实现才500多行代码。这是多么轻量级的一个类库,只不过代码这么短,功能也不会太多,相比laravel的依赖注入而言,它的功能就单一太多了。不过没关系,相比Guice而言这些缺失的功能不是必须的,能帮我们省掉很多代码它已经做得很好了,这就足够了。

所以最上面的代码就可以修改为:

    var userController controllers.UserController
    var injector inject.Graph
    _ = injector.Provide(
        &inject.Object{Value: &repositories.UserManagerRepository{Db: models.MysqlHandler}},
        &inject.Object{Value: &services.UserService{}},
        &inject.Object{Value: &userController},
    )
    _ = injector.Populate()

在gin使用依赖注入

func TestInject(t *testing.T) {
    models.Init()
    models.MysqlHandler.AutoMigrate(models.User{})
    //使用 Inject New方法就不用写了
    var userController controllers.UserController
    var injector inject.Graph
    _ = injector.Provide(
        &inject.Object{Value: &repositories.UserManagerRepository{Db: models.MysqlHandler}},
        &inject.Object{Value: &services.UserService{}},
        &inject.Object{Value: &userController},
    )
    _ = injector.Populate()

    app := gin.Default()
    api := app.Group("/api")
    {
        api.POST("/login", userController.Login)
        api.POST("/register", userController.Register)
        api.GET("/me", middleware.Auth(), userController.Info)
    }
    _ = app.Run(":8080")
}

func TestNoInject(t *testing.T) {
    models.Init()
    models.MysqlHandler.AutoMigrate(models.User{})
    //不使用 Inject
    repository := repositories.NewUserRepository()
    userServices := services.NewUserServices(repository)
    controller := controllers.NewUserController(userServices)

    app := gin.Default()
    api := app.Group("/api")
    {
        api.POST("/login", controller.Login)
        api.POST("/register", controller.Register)
        api.GET("/me", middleware.Auth(), controller.Info)
    }
    _ = app.Run(":8080")
}

源码:https://github.com/myxy99/shopping

本文使用CC BY-NC-SA 3.0 中国大陆协议许可
本文链接:https://myxy99.cn/posts/golang/8f49d9e3.html