既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
在现代软件开发中,依赖注入(Dependency Injection,简称 DI)已经成为一种广泛采用的设计模式。它的核心思想是通过外部定义的方式,将组件之间的依赖关系解耦,从而提高代码的可维护性、可扩展性和可测试性。然而,随着项目规模的增长,手动管理复杂的依赖关系变得日益困难。这时,依赖注入代码生成工具就显得尤为重要。在众多工具中,Wire 以其简洁、强大和易用性脱颖而出,成为 Go 语言项目中的宠儿。本文将带你深入了解 Wire 的安装、基本使用、核心概念以及高级用法,并通过一个实际的 web 博客项目示例,展示如何利用 Wire 简化依赖注入的实现。准备好了吗?让我们开始这场代码解耦的奇妙之旅。
Wire 的安装与基本使用
安装 Wire
首先,我们需要安装 Wire。在 Go 环境中,安装过程非常简单:
go install github.com/google/wire/cmd/wire@latest
请确保你的 $GOPATH/bin
已经添加到了环境变量 $PATH
中。
前置代码准备
在开始使用 Wire 之前,我们需要准备一些前置代码。这通常包括定义项目中所需的类型、接口以及初始化函数。以下是一个简单的 web 博客项目的代码示例:
// handler.go
package handler
import (
"net/http"
"github.com/gin-gonic/gin"
)
type PostHandler struct {
serv service.IPostService
}
func (h \*PostHandler) RegisterRoutes(engine \*gin.Engine) {
engine.GET("/post/:id", h.GetPostById)
}
func (h \*PostHandler) GetPostById(ctx \*gin.Context) {
content := h.serv.GetPostById(ctx, ctx.Param("id"))
ctx.String(http.StatusOK, content)
}
func NewPostHandler(serv service.IPostService) \*PostHandler {
return &PostHandler{serv: serv}
}
// service.go
package service
import "context"
type IPostService interface {
GetPostById(ctx context.Context, id string) string
}
type PostService struct{}
func (s \*PostService) GetPostById(ctx context.Context, id string) string {
return "欢迎关注本掘金号,作者:陈明勇"
}
func NewPostService() IPostService {
return &PostService{}
}
// ioc.go
package ioc
import (
"github.com/gin-gonic/gin"
"chenmingyong0423/blog/tutorial-code/wire/internal/post/handler"
"chenmingyong0423/blog/tutorial-code/wire/internal/post/service"
)
func NewGinEngineAndRegisterRoute(postHandler \*handler.PostHandler) \*gin.Engine {
engine := gin.Default()
postHandler.RegisterRoutes(engine)
return engine
}
使用 Wire 生成代码
在准备好前置代码后,我们需要创建一个名为 wire.go
的配置文件。在这个文件中,我们将定义注入器函数,用于指引 Wire 生成依赖注入代码。
// wire.go
//go:build wireinject
// +build wireinject
package wire
import (
"chenmingyong0423/blog/tutorial-code/wire/internal/post/handler"
"chenmingyong0423/blog/tutorial-code/wire/internal/post/service"
"chenmingyong0423/blog/tutorial-code/wire/internal/post/ioc"
)
func InitializeApp() (\*gin.Engine, func() error) {
wire.Build(
handler.NewPostHandler,
service.NewPostService,
ioc.NewGinEngineAndRegisterRoute,
)
}
在 wire.go
文件的首行,我们使用了 //go:build wireinject
注释,这告诉 Go 编译器只有在使用 Wire 工具时才编译这部分代码。
接下来,在 wire.go
文件所在目录下执行以下命令,Wire 将自动生成 wire_gen.go
文件,其中包含了依赖注入的代码。
go run github.com/google/wire/cmd/wire
Wire 的核心概念
Wire 的核心概念包括提供者(Providers)和注入器(Injectors)。提供者是能够产生值的函数,而注入器则负责将所有提供者连接起来,完成依赖注入。
Wire 提供者(Providers)
提供者是一个有返回值的函数。在 Wire 中,我们可以通过 wire.NewSet
函数将多个提供者进行分组。例如,我们可以将与文章相关的提供者进行组合:
PostSet := wire.NewSet(NewPostHandler, service.NewPostService)
Wire 注入器(Injectors)
注入器的作用是连接所有的提供者。在之前的 InitializeApp
函数中,我们定义了一个注入器,它通过 wire.Build
方法连接了所有的提供者。
Wire 的高级用法
Wire 提供了多种高级用法,包括绑定接口、结构体提供者、绑定值、使用结构体字段作为提供者、清理函数等。
绑定接口
在 Wire 中,我们可以通过 wire.Bind
建立接口类型和具体实现类型之间的绑定关系。这在处理接口依赖时非常有用。
wire.Build(
service.NewPostServiceV2,
wire.Bind(new(service.IPostService), (\*service.PostService)),
)
结构体提供者(Struct Providers)
Wire 的 wire.Struct
函数可以根据现有的类型构造结构体。这在需要根据类型字段进行依赖注入时非常有用。
user := &User{
MyName: name,
MyPublicAccount: publicAccount,
}
wire.Struct(user, "MyName", "MyPublicAccount")
绑定值
有时候,我们可能需要直接在注入器中为一个类型赋值,而不是依赖提供者。这时,我们可以使用 wire.Value
来实现。
InjectUser := wire.Value(User{MyName: "陈明勇"})
使用结构体字段作为提供者
在某些情况下,我们可以使用结构体的某个字段作为提供者,从而生成一个类似 GetXXX
的函数。
wire.FieldsOf(&user, "MyName")
清理函数
如果一个提供者创建了需要清理的资源,它可以返回一个闭包来清理资源。注入器会用它来给调用者返回一个聚合的清理函数。
func provideFile(log Logger, path Path) (\*os.File, func() error) {
f, err := os.Open(path)
if err != nil {
return nil, func() error { return err }
}
cleanup := func() error {
return f.Close()
}
return f, cleanup
}
备用注入器语法
Wire 还提供了备用注入器语法,允许我们以更简洁的方式编写注入器函数。
InitializeGin := wire.Build(
/\* ... \*/
)
实战应用:构建一个简单的 Web 博客项目
为了更好地理解 Wire 的实际应用,我们将通过构建一个简单的 Web 博客项目来展示 Wire 的强大功能。这个项目将包括文章的获取、展示以及依赖注入的实现。
项目结构
首先,我们需要规划项目的结构。一个典型的 Go 项目结构可能如下所示:
/my-blog-project
/cmd
/main.go
/internal
/post
handler.go
service.go
ioc.go
/user
// 其他模块...
/config
// 配置文件...
/wire
wire.go
// 其他目录...
定义服务接口和实现
在 /internal/post/service.go
中,我们定义了 IPostService
接口及其实现:
package service
type IPostService interface {
GetPostById(id string) (string, error)
}
type PostService struct{}
func (s \*PostService) GetPostById(id string) (string, error) {
// 实现获取文章的逻辑
return "文章内容", nil
}
创建 HTTP 处理程序
在 /internal/post/handler.go
中,我们创建了 PostHandler
结构体,它包含了处理 HTTP 请求的方法:
package handler
import (
"net/http"
"github.com/gin-gonic/gin"
)
type PostHandler struct {
postService IPostService
}
func (h \*PostHandler) GetPost(w http.ResponseWriter, r \*http.Request) {
id := r.URL.Query().Get("id")
post, err := h.postService.GetPostById(id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write([]byte(post))
}
func NewPostHandler(postService IPostService) \*PostHandler {
return &PostHandler{postService: postService}
}
初始化 Gin 引擎并注册路由
在 /internal/post/ioc.go
中,我们初始化 Gin 引擎并注册路由:
package ioc
import (
"github.com/gin-gonic/gin"
"my-blog-project/internal/post/handler"
)
func NewGinEngine() \*gin.Engine {
engine := gin.Default()
postHandler := NewPostHandler(&service.PostService{})
engine.GET("/posts/:id", postHandler.GetPost)
return engine
}
使用 Wire 生成依赖注入代码
现在,我们可以在 wire.go
中定义注入器函数,并使用 Wire 生成依赖注入代码:
// wire.go
//go:build wireinject
// +build wireinject
package wire
import (
"my-blog-project/cmd"
"my-blog-project/internal/post/handler"
"my-blog-project/internal/post/service"
"my-blog-project/internal/post/ioc"
)
func InitializeApp() (\*cmd.Server, error) {
wire.Build(
ioc.NewGinEngine,
cmd.NewServer,
)
}
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
/ioc"
)
func InitializeApp() (*cmd.Server, error) {
wire.Build(
ioc.NewGinEngine,
cmd.NewServer,
)
}
[外链图片转存中...(img-2sik7N6n-1715496562211)]
[外链图片转存中...(img-FRKBY0XJ-1715496562211)]
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**