手把手,带你从零封装Gin框架(十二):使用 Wire 依赖注入重构

2024-01-23 15:56:38 浏览数 (2)

前言

由于之前项目中各个组件都是通过全局变量传递的,随着项目的推进,一大堆全局变量会混成一团,如果一不小心在某个地方对全局变量进行修改将可能引发严重的 panic,便打算使用依赖注入重构一下, Wire 是一个灵活的依赖注入工具,能够帮助我们在程序编译期就完成依赖注入。

依赖注入简述

依赖注入是指组件在创建时,就应该获取该组件所依赖的其他关系,如下代码所示,要创建一个 App 实例需要 ConfigServer 结构体,分别展示使用与未使用依赖注入的两种方式。

代码语言:javascript复制
type App struct {
    conf *Config
    httpServer *Server
}

// 构建 Config
func InitConfig() *Config {
    return &Config{}
}

// 构建 Server
func NewHttpServer() *Server {
    return &Server{}
}

// 构建 App (内部调用依赖组件的构建函数)
func NewApp() *App {
    return &App{
        conf: InitConfig(),
        httpServer: NewHttpServer(),
    }
}

// 构建 App (需由调用者传入依赖组件)
func NewAppByDI(conf *Config, httpSrv *Server) *App {
    return &App{
        conf: conf,
        httpServer: httpSrv,
    }
}

func main() {
    // 未使用依赖注入
    app := NewApp()
  
    // 使用依赖注入
    config := InitConfig()
    server := NewHttpServer()
    app := NewAppByDI(config, server)
}
  • • 未使用依赖注入的情况下,调用者无法知道 App 内部使用了 ConfigServer ,如果 Config 构建函数 InitConfig() 发生变化,假设需要增加一个参数,我们就需要在每个调用 InitConfig() 的地方修改代码。
  • • 使用依赖注入的情况下,将 ConfigServer 的构建逻辑与构建 App 的逻辑分离开,即使 Config 的构建函数 InitConfig 发生了变化,也只需要修改一处代码,但是在构建 App 之前,需要手动构建 ConfigServer ,随着程序推进,这些依赖关系将越来越复杂,这时候就需要依赖注入工具 Wire 来帮助我们生成依赖关系。

安装工具

代码语言:javascript复制
# 导入项目
go get -u github.com/google/wire

# 安装命令
go install github.com/google/wire/cmd/wire

工作原理简述

Wire 有两个核心概念 ProviderInjector

Provider 就是各组件的构建函数,这些函数需要接收依赖的组件为参数,创建组件并返回,就是上面例子中的 NewAppByDI() 函数。

Injector 是由 Wire 自动生成的函数,它会根据依赖的顺序调用 Provider,为了生成该函数,通常在 wire.go 文件中定义 Injector 函数签名,在其函数内部调用 wire.Build() ,并以所需 Provider 作为参数(无须考虑顺序)。

重构

这里只简单展示一下 wire.go 文件,主要工作就是先为之前项目中使用的各个组件都编写 Provider 函数,然后在 wire.Build() 中传入各个 Provider 即可,完整代码请查看 https://github.com/jassue/jassue-gin/tree/main。

代码语言:javascript复制
//go:build wireinject
//  build wireinject

package main

import (
    "github.com/google/wire"
    "github.com/jassue/gin-wire/app/compo"
    "github.com/jassue/gin-wire/app/cron"
    "github.com/jassue/gin-wire/app/data"
    "github.com/jassue/gin-wire/app/handler"
    "github.com/jassue/gin-wire/app/service"
    "github.com/jassue/gin-wire/config"
    "github.com/jassue/gin-wire/router"
    "go.uber.org/zap"
    "gopkg.in/natefinch/lumberjack.v2"
)

// wireApp init application.
func wireApp(*config.Configuration, *lumberjack.Logger, *zap.Logger) (*App, func(), error) {
    panic(wire.Build(data.ProviderSet, compo.ProviderSet, service.ProviderSet, handler.ProviderSet, router.ProviderSet, cron.ProviderSet, newHttpServer, newApp))
}

0 人点赞