运行时依赖
安装命令
点击复制技能文档
角色:您是一位使用dig构建应用程序图的Go架构师。您将容器保持在组合根,依赖于接口而不是具体类型,并将构造函数错误视为一等失败。使用uber-go/dig进行Go的依赖注入,反射基于DI工具包,旨在为应用程序框架提供动力(它是uber-go/fx背后的引擎),并在启动期间解析对象图。官方资源:pkg.go.dev/go.uber.org/dig github.com/uber-go/dig 本技能并不详尽。请参考库文档和代码示例以获取更多信息。Context7可以作为发现平台提供帮助。go get go.uber.org/dig dig与fx的比较 fx是建立在dig之上的,并且共享相同的容器引擎——DI原语(Provide、Invoke、In/Out结构、命名值、值组)是相同的。fx.In/fx.Out是dig.In/dig.Out的重新导出。fx在dig之上添加了什么:关注点 dig fx DI容器 √ dig.New() √(嵌入) 生命周期钩子 × √ fx.Lifecycle OnStart/OnStop 模块系统 × √ fx.Module带有作用域装饰器 信号感知运行循环 × √ app.Run()阻塞在SIGINT/SIGTERM 结构化事件日志 × √ fx.WithLogger / fxevent 启动/关闭超时 × √ fx.StartTimeout / fx.StopTimeout 当您只需要绘制图时,请选择dig:CLI工具、向调用者公开容器的库、测试工具或将DI嵌入到管理其自身生命周期的现有应用程序中。对于长期运行的服务(HTTP服务器、工作人员、守护程序),请选择fx——生命周期和信号处理是不可协商的。请参阅samberg/cc-skills-golang@golang-uber-fx技能。容器导入“go.uber.org/dig” c:= dig.New() 有用的选项:dig.DeferAcyclicVerification()(更快的启动)、dig.RecoverFromPanics()(将panic转换为dig.PanicError)、dig.DryRun(true)(验证而不调用)。提供和调用 //注册一个构造函数——懒惰,只在其输出需要时运行 err:= c.Provide(func(cfg Config) (sql.DB, error) { return sql.Open("postgres", cfg.DSN) }) //通过要求它作为函数参数来从容器中提取服务 err = c.Invoke(func(db sql.DB) error { return db.Ping() }) 构造函数是懒惰和记忆的:每个输出类型只构建一次并共享(每个容器的单例)。在注册时提供错误,如果构造函数有问题;调用返回构造函数的错误,包装了触发它的依赖路径。dig构造函数可以是任何函数。输入是依赖项,输出是提供的类型。错误(最后返回)表示构造失败。遵循“接受接口,返回结构”。参数对象与dig.In 一旦构造函数有4+个依赖项,请嵌入dig.In将它们分组为结构字段并标记字段:type HandlerParams struct { dig.In Logger zap.Logger DB sql.DB Cache redis.Client optional:"true" //如果未提供,则为零值 DBRO sql.DB name:"readonly" //命名依赖项 Routes []http.Handler group:"routes" //值组 } func NewHandler(p HandlerParams) Handler { / ... / } 标签:name:“...”,optional:“true”,group:“...”。结果对象与dig.Out 从一个构造函数返回多个值并将名称/组标签附加到结果:type ConnResult struct { dig.Out ReadWrite sql.DB name:"primary" ReadOnly sql.DB name:"readonly" } func NewConnections(cfg Config) (ConnResult, error) { / ... / } 命名值 同一类型的两个提供者发生冲突。使用dig.Name进行消歧:c.Provide(NewPrimaryDB, dig.Name("primary")) c.Provide(NewReadOnlyDB, dig.Name("readonly")) 通过在dig.In字段中添加name:“primary”/name:“readonly”来使用。值组 多个提供者,一个消费者切片——对于HTTP处理程序、运行状况检查和迁移来说很常见:type RouteResult struct { dig.Out Handler http.Handler group:"routes" } func NewUserHandler(db sql.DB) RouteResult { / ... / } func NewPostHandler(db sql.DB) RouteResult { / ... / } type ServerParams struct { dig.In Routes []http.Handler group:"routes" } 扁平化——追加,flatten(例如group:“routes,flatten”)来展开切片而不是嵌套它。组的顺序不保证;如果顺序很重要,请从单个构造函数提供一个显式的有序切片。作为接口提供(dig.As)注册一个具体的构造函数并在一个或多个接口下公开它,而无需单独的适配器:c.Provide(NewPostgresDB, dig.As(new(Database), new(io.Closer))) //消费者要求Database或io.Closer;PostgresDB保持隐藏。完整的应用程序示例 func main() { c := dig.New() must(c.Provide(NewConfig)) must(c.Provide(NewLogger)) must(c.Provide(NewDatabase)) must(c.Provide(NewServer)) err := c.Invoke(func(srv *http.Server) error { return srv.ListenAndServe() }) if err != nil { log.Fatal(err) } } func must(err error) { if err != nil { panic(err) } } dig没有内置的生命周期。如果您需要它,请使用fx。