You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Go的Wire依赖注入框架中为不同提供者配置专属zap.Logger实例

Google Wire 同类型多实例注入与运行时参数融合方案

Wire 基于类型匹配依赖,要实现同类型不同实例注入、以及编译期配置和运行时变量的融合,可按以下步骤实现:


核心思路

  • 对同类型的不同依赖,通过类型别名做唯一标识,解决Wire按类型匹配的冲突问题
  • 运行时生成的变量(根日志、配置、密钥等)直接作为注入器的入参传入,Wire会自动将其纳入依赖树
  • 通过适配层将别名类型转换为原有工厂需要的原生类型,无需修改业务代码

具体实现步骤

1. 定义类型别名区分Logger

为每个服务需要的Logger定义独立的类型别名:

// 放在wire配置文件中
type UserDaoLogger *zap.Logger
type JWTServiceLogger *zap.Logger
type LoginServiceLogger *zap.Logger

2. 编写Logger适配Provider

将运行时传入的根Logger转换为对应别名类型的带命名的Logger实例:

func provideUserDaoLogger(root *zap.Logger) UserDaoLogger {
    return UserDaoLogger(root.Named("dao.user"))
}

func provideJWTServiceLogger(root *zap.Logger) JWTServiceLogger {
    return JWTServiceLogger(root.Named("service.jwt"))
}

func provideLoginServiceLogger(root *zap.Logger) LoginServiceLogger {
    return LoginServiceLogger(root.Named("service.login"))
}

3. 更新ProviderSet

保留原有绑定和工厂,新增适配Provider和参数绑定:

var AppSet = wire.NewSet(
    // 原有接口绑定
    wire.Bind(new(interfaces.LoginService), new(*service.LoginServiceImpl)),
    wire.Bind(new(interfaces.JWTService), new(*service.JWTServiceImpl)),
    wire.Bind(new(interfaces.UserDao), new(*dao.UserDaoImpl)),
    // 原有工厂
    service.NewLoginService,
    service.NewJWTService,
    dao.NewUserDao,
    database.Connect,
    // 新增Logger适配Provider
    provideUserDaoLogger,
    provideJWTServiceLogger,
    provideLoginServiceLogger,
    // 给指定工厂绑定对应Logger(无需修改原有工厂代码)
    wire.Bind(new(*zap.Logger), new(UserDaoLogger)).For(dao.NewUserDao),
    wire.Bind(new(*zap.Logger), new(JWTServiceLogger)).For(service.NewJWTService),
    wire.Bind(new(*zap.Logger), new(LoginServiceLogger)).For(service.NewLoginService),
)

如果你的Wire版本不支持.For()参数绑定,也可以写包装工厂替代:

func wrapNewUserDao(db *gorm.DB, logger UserDaoLogger) interfaces.UserDao {
    return dao.NewUserDao(db, (*zap.Logger)(logger))
}
// 将ProviderSet中的dao.NewUserDao替换为wrapNewUserDao即可

4. 定义注入器函数

将所有运行时参数作为注入器的入参:

//go:build wireinject
// +build wireinject

package yourpkg

import "github.com/google/wire"

func InitializeApp(
    mysqlConfig interfaces.MySQLConfig, // 运行时加载的数据库配置
    rootLogger *zap.Logger, // 运行时创建的根日志
    jwtKey [32]byte, // 运行时读取的JWT密钥
) (interfaces.LoginService, error) {
    wire.Build(AppSet)
    return nil, nil
}

5. 调用注入器

在入口main函数中传入运行时生成的变量即可:

func main() {
    // 运行时创建根日志
    logger, err := zap.NewDevelopment()
    if err != nil {
        panic(err)
    }
    defer logger.Sync()

    // 运行时加载配置
    mysqlConfig := loadMySQLConfig()
    jwtKey := loadJWTKey()

    // 直接调用Wire生成的注入器,自动完成所有依赖组装
    loginService, err := InitializeApp(mysqlConfig, logger, jwtKey)
    if err != nil {
        panic(err)
    }

    // 业务逻辑使用loginService即可
}

内容的提问来源于stack exchange,提问作者Naftuli Kay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 17:09:01