Skip to content

wire 依赖注入架构

在 Go 中使用 GinGormWire 来进行依赖注入和三层架构设计是常见的做法。这里,我会展示如何使用三层架构(ControllerServiceRepository)来组织代码,并通过 Wire 实现依赖注入。这样做可以使代码更加模块化,便于扩展和维护。

三层架构简介

  1. Controller:接收请求并响应,它负责请求和响应的处理,调用 Service 层来执行业务逻辑。
  2. Service:处理具体的业务逻辑,通常是调用 Repository 层来访问数据。
  3. Repository:与数据库交互,封装了 Gorm 的 CRUD 操作。

示例结构

/app
    ├── controller
    │   └── user_controller.go
    ├── service
    │   └── user_service.go
    └── repository
        └── user_repository.go
/wire.go
/main.go

1. 创建 Gorm 模型

首先,我们定义一个 User 模型,用 Gorm 来进行数据存取。

go
// /app/repository/user_repository.go
package repository

import (
	"gorm.io/gorm"
)

// User 模型
type User struct {
	ID   uint   `gorm:"primaryKey"`
	Name string `gorm:"size:255"`
	Age  uint
}

// UserRepository 提供与数据库交互的操作
type UserRepository struct {
	DB *gorm.DB
}

// NewUserRepository 创建 UserRepository
func NewUserRepository(db *gorm.DB) *UserRepository {
	return &UserRepository{DB: db}
}

// GetUserByID 获取用户
func (r *UserRepository) GetUserByID(id uint) (*User, error) {
	var user User
	if err := r.DB.First(&user, id).Error; err != nil {
		return nil, err
	}
	return &user, nil
}

// CreateUser 创建用户
func (r *UserRepository) CreateUser(user *User) error {
	return r.DB.Create(user).Error
}

2. 创建 Service 层

UserService 层负责具体的业务逻辑,它会调用 UserRepository 进行数据库操作。

go
// /app/service/user_service.go
package service

import (
	"gin-wire-example/app/repository"
)

// UserService 提供与业务逻辑相关的操作
type UserService struct {
	Repo *repository.UserRepository
}

// NewUserService 创建 UserService
func NewUserService(repo *repository.UserRepository) *UserService {
	return &UserService{Repo: repo}
}

// GetUserByID 获取用户信息
func (s *UserService) GetUserByID(id uint) (*repository.User, error) {
	return s.Repo.GetUserByID(id)
}

// CreateUser 创建用户
func (s *UserService) CreateUser(user *repository.User) error {
	return s.Repo.CreateUser(user)
}

3. 创建 Controller 层

UserController 层负责 HTTP 请求的接收和响应,并调用 UserService 来处理业务。

go
// /app/controller/user_controller.go
package controller

import (
	"github.com/gin-gonic/gin"
	"gin-wire-example/app/service"
	"net/http"
	"strconv"
)

// UserController 提供与 HTTP 请求相关的操作
type UserController struct {
	Service *service.UserService
}

// NewUserController 创建 UserController
func NewUserController(service *service.UserService) *UserController {
	return &UserController{Service: service}
}

// GetUser 获取用户信息
func (c *UserController) GetUser(ctx *gin.Context) {
	id, err := strconv.Atoi(ctx.Param("id"))
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
		return
	}

	user, err := c.Service.GetUserByID(uint(id))
	if err != nil {
		ctx.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
		return
	}

	ctx.JSON(http.StatusOK, user)
}

// CreateUser 创建用户
func (c *UserController) CreateUser(ctx *gin.Context) {
	var user service.User
	if err := ctx.ShouldBindJSON(&user); err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid data"})
		return
	}

	if err := c.Service.CreateUser(&user); err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})
		return
	}

	ctx.JSON(http.StatusCreated, user)
}

4. 使用 Wire 进行依赖注入

wire.go 中定义依赖关系,并利用 Wire 自动生成代码来注入依赖。

go
// /wire.go
//+build wireinject

package main

import (
	"gin-wire-example/app/controller"
	"gin-wire-example/app/repository"
	"gin-wire-example/app/service"
	"github.com/google/wire"
	"gorm.io/gorm"
)

// Set 提供依赖集合
var Set = wire.NewSet(
	NewDB,                       // 创建数据库连接
	repository.NewUserRepository, // 创建 UserRepository
	service.NewUserService,       // 创建 UserService
	controller.NewUserController, // 创建 UserController
)

// InitializeApp 初始化应用
func InitializeApp() (*controller.UserController, error) {
	wire.Build(Set)
	return nil, nil
}

// NewDB 创建 Gorm 数据库连接
func NewDB() (*gorm.DB, error) {
	// 这里假设已经配置了数据库连接
	// db, err := gorm.Open(...)

	return &gorm.DB{}, nil // 实际上应返回连接的数据库实例
}

5. 主程序启动

main.go 中,使用 Wire 初始化应用并启动 Gin 服务。

go
// /main.go
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
)

func main() {
	// 初始化控制器
	controller, err := InitializeApp()
	if err != nil {
		log.Fatal(err)
	}

	// 创建 Gin 路由
	router := gin.Default()

	// 路由配置
	router.GET("/users/:id", controller.GetUser)
	router.POST("/users", controller.CreateUser)

	// 启动 Gin
	if err := router.Run(":8080"); err != nil {
		log.Fatal("Error starting server:", err)
	}
}

6. 运行 wire 命令生成代码

在项目根目录运行以下命令来生成 wire_gen.go 文件:

bash
wire

wire_gen.go 文件将自动生成,完成所有依赖的注入和初始化。

总结

  • 三层架构:我们将代码分为 Controller、Service 和 Repository 层。Controller 层处理 HTTP 请求,Service 层处理业务逻辑,Repository 层与数据库交互。
  • 依赖注入:通过 Wire,我们自动注入每一层的依赖,避免了手动管理依赖关系。
  • 数据库操作:通过 Gorm 在 Repository 层进行数据库操作。Wire 负责创建和注入数据库连接。

通过这种方式,我们将 Go + Gin + Gorm + Wire 的组合用于开发应用程序,确保了代码的模块化、可维护性和清晰的依赖关系管理。