Go 依赖注入库wire基本使用

 更新时间:2026年03月31日 09:32:06   作者:小黑随笔  
本文主要介绍了Go 依赖注入库wire基本使用,使用Wire工具简化依赖初始化的过程,通过依赖注入,代码更加模块化、可测试,并减少了各模块之间的耦合,增强了可维护性,Wire工具自动生成依赖代码,使开发更加高效

前言

学习过Java 开发的同学,一定对依赖注入有所耳闻。依赖注入(Dependency Injection,简称 DI)是一种设计模式,通过将组件依赖项外部化,使代码更加模块化和易于测试。对于Wire的使用,可以使得开发人员不用在手写对应实例的创建,只需要规范化的编写对应的依赖代码,并通过wire gen 对应目录即可生成对应的实例创建代码。

一、什么是依赖注入

依赖注入是一种设计模式,用于将对象的依赖关系通过构造函数、方法或属性注入,而不是在对象内部创建依赖。这样可以提高代码的可测试性和灵活性。

1 举个栗子

比如在Web开发中,常用的一些设计模式,都会将业务分层多个层去处理,比如MVC结构,在Controller层就要调用Service层的业务,而Service层又需要dao。这种存在依赖的关系,在创建实例时,不是在内部创建,而是通过注入就是依赖注入。

package main
import "fmt"
type Dao struct {
}
func NewDao() *Dao {
	return &Dao{}
}
func (d *Dao) Do() {
	fmt.Println("do dao")
}
// 实现接口的结构体
type Service struct {
	dao *Dao
}
func NewService(dao *Dao) *Service {
	return &Service{
		dao: dao,
	}
}
func (s *Service) Execute() {
	fmt.Println("Executing service...")
	s.dao.Do()
}
// 使用依赖注入的结构体
type Controller struct {
	service *Service
}
func NewController(s *Service) *Controller {
	return &Controller{service: s}
}
func (c *Controller) Run() {
	c.service.Execute()
}
func main() {
	daoDao := dao.NewDao()
	serviceService := service.NewService(daoDao)
	controllerController := controller.NewController(serviceService)
	controller.Run()
}

如上述代码中的main函数中的内容就是依赖注入的形式

dao := NewDao()
service := NewService(dao)
// service 通过传入的方式进入到Controller中,而不是内部创建
controller := NewController(service)
controller.Run()

2. 依赖注入的好处

依赖注入的好处包括:

  1. 可测试性:可以轻松替换依赖,进行单元测试。
  2. 解耦合:减少模块之间的直接依赖,增强代码灵活性。
  3. 易于维护:更改依赖时无需修改使用它的代码。
  4. 可复用性:相同的依赖可以在多个地方使用,提高代码复用性。
  5. 更清晰的代码结构:依赖注入有助于明确对象之间的关系,使得代码结构更加清晰,易于理解。

二、Wire

Wire 是一个专为依赖注入(Dependency Injection)设计的代码生成工具,它可以自动生成用于初始化各种依赖关系的代码,从而帮助我们更轻松地管理和注入依赖关系。

1.使用wire的前置条件

使用wire需要两个前置条件:

  1. wire命令安装
  2. golang中使用 wire 提供者生成函数

安装wire命令

go install github.com/google/wire/cmd/wire@latest

代码导入wire

使用 Go 的包管理工具安装 Wire:

go get github.com/google/wire

创建Wire生成函数

// +build wireinject
package main
import "github.com/google/wire"
func InitializeController() *Controller {
    wire.Build(NewMyService, NewController)
    return &Controller{}
}

2.小试牛刀

刚才main中的代码,分别拆分出来,这样更符合实际的开发场景。

├─controller
├─dao
├─service
└─wiretest

每个部分的代码

controller/controller.go

package controller
import "wirelearn/service"
// 使用依赖注入的结构体
type Controller struct {
	service *service.Service
}
func NewController(s *service.Service) *Controller {
	return &Controller{service: s}
}
func (c *Controller) Run() {
	c.service.Execute()
}

dao/dao.go

package dao
import "fmt"
type Dao struct {
}
func NewDao() *Dao {
	return &Dao{}
}
func (d *Dao) Do() {
	fmt.Println("do dao")
}

service/service.go

package service
import (
	"fmt"
	"wirelearn/dao"
)
// 实现接口的结构体
type Service struct {
	dao *dao.Dao
}
func NewService(dao *dao.Dao) *Service {
	return &Service{
		dao: dao,
	}
}
func (s *Service) Execute() {
	fmt.Println("Executing service...")
	s.dao.Do()
}

wiretest/wire.go

//go:build wireinject
// +build wireinject
package wiretest
import (
	"github.com/google/wire"
	"wire-learn/wirelearn/dao"
	"wire-learn/wirelearn/controller"
	"wire-learn/wirelearn/service"
)
var providerSet = wire.NewSet(
	controller.NewController,
	service.NewService,
	dao.NewDao,
)
func Initialize() (*controller.Controller, error) {
	panic(wire.Build(providerSet))
}

wire.go文件中,我们只需要把生成实例的方法指针放到wire.NewSet中,就完成主要作用wire的编写,Initialize方法的返回就是我们要给的最终实例
main.go

func main() {
	controller, err := wiretest.Initialize()
	if err != nil {
		panic(err)
	}
	controller.Run()
}

main中,我们只需要调用wiretest.Initialize中的方法获取对应的实例。这块就是wire自动生成的代码,通常和wire.go在同一个文件夹中
看下我们生成的wire_gen.go的代码吧

// Code generated by Wire. DO NOT EDIT.
//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package wiretest
import (
	"github.com/google/wire"
	"wirelearn/controller"
	"wirelearn/dao"
	"wirelearn/service"
)
// Injectors from wire.go:
func Initialize() (*controller.Controller, error) {
	daoDao := dao.NewDao()
	serviceService := service.NewService(daoDao)
	controllerController := controller.NewController(serviceService)
	return controllerController, nil
}
// wire.go:
var providerSet = wire.NewSet(controller.NewController, service.NewService, dao.NewDao)

可以看到Initialize方法中的代码和我们没使用wire之前,在main方法中写的,基本相同。所以我们也可以大致了解wire在实际任务中实际工作方式。

总结

本文通过示例讲解了依赖注入的原理及其在 Go 语言中的实际应用,尤其是利用 Wire 工具自动生成依赖代码的过程。通过依赖注入,代码更加模块化、可测试,并减少了各模块之间的耦合,增强了可维护性。 Wire 工具进一步简化了这个过程,避免了繁琐的手动编写依赖初始化代码。

到此这篇关于Go 依赖注入库wire基本使用的文章就介绍到这了,更多相关Go 依赖注入库wire内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • go学习笔记读取consul配置文件详解

    go学习笔记读取consul配置文件详解

    这篇文章主要为大家介绍了go学习笔记读取consul配置文件详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • Go语言的文件名、标识符、关键字和包基础教程

    Go语言的文件名、标识符、关键字和包基础教程

    Go的关键字不能被用作标识符,这是一个重要的限制,以避免命名冲突和语法混淆,这篇文章主要给大家介绍了关于Go语言文件名、标识符、关键字和包的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-06-06
  • 聊聊Golang中很好用的viper配置模块

    聊聊Golang中很好用的viper配置模块

    这篇文章主要介绍了Golang中很好用的viper配置模块用法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • 重学Go语言之如何使用Redis

    重学Go语言之如何使用Redis

    Redis是我们开发应用程序中很常用的NoSQL数据库,那么在Go语言中要如何连接和操作Redis呢,在这篇文章中,我们就来一起来探究一下吧
    2023-08-08
  • Go语言学习之循环语句使用详解

    Go语言学习之循环语句使用详解

    这篇文章主要为大家介绍了Go语言中的常用循环语句的使用,例如:for循环、for-each、break等,文中的示例代码讲解详细,感兴趣的可以了解一下
    2022-04-04
  • 一文秒懂Go 编写命令行工具的代码

    一文秒懂Go 编写命令行工具的代码

    这篇文章主要介绍了一文秒懂Go 编写命令行工具的代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • Go Excelize API源码阅读SetSheetViewOptions示例解析

    Go Excelize API源码阅读SetSheetViewOptions示例解析

    这篇文章主要为大家介绍了Go-Excelize API源码阅读SetSheetViewOptions示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • Go语言入门之基础语法和常用特性解析

    Go语言入门之基础语法和常用特性解析

    这篇文章主要给大家讲解了Go语言的基础语法和常用特性解析,比较适合入门小白,文中通过代码示例介绍的非常详细,对我们学习Go语言有一定的帮助,需要的朋友可以参考下
    2023-07-07
  • 浅析GO语言的垃圾回收机制

    浅析GO语言的垃圾回收机制

    今天我们来聊聊golang是如何进行垃圾回收的,我们知道,目前各语言进行垃圾回收的方法有很多,如引用计数、标记清除、分代回收、三色标记等,各种方式都有其特点,文中介绍的非常详细,感兴趣的小伙伴跟着小编一起学习吧
    2023-07-07
  • 使用Go语言实现的WebDAV内存文件系统

    使用Go语言实现的WebDAV内存文件系统

    这篇文章主要为大家详细介绍了如何使用Go语言实现的WebDAV内存文件系统,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-11-11

最新评论