A reflection based dependency injection toolkit for Go.

⚒️ dig GoDoc GitHub release Build Status Coverage Status Go Report Card

A reflection based dependency injection toolkit for Go.

Good for:

  • Powering an application framework, e.g. Fx.
  • Resolving the object graph during process startup.

Bad for:

  • Using in place of an application framework, e.g. Fx.
  • Resolving dependencies after the process has already started.
  • Exposing to user-land code as a Service Locator.

Installation

We recommend consuming SemVer major version 1 using your dependency manager of choice.

$ glide get 'go.uber.org/dig#^1'
$ dep ensure -add "go.uber.org/dig@v1"
$ go get 'go.uber.org/dig@v1'

Stability

This library is v1 and follows SemVer strictly.

No breaking changes will be made to exported APIs before v2.0.0.

Owner
Uber Go
Uber's open source software for Go development
Uber Go
Comments
  • Allow to specify an interface when providing a constructor

    Allow to specify an interface when providing a constructor

    Update (by @glibsm)

    The addition of dig.As ProvideOption has been agreed on.


    Currently dig only uses a constructors that returns exactly what the function expects.

    If the function accepts an interface, and we don't inject the constructor that returns that interface we get this error

    panic: missing dependencies for function "main".main.func1 (..../main.go:29): type main.Fooer is not in the container, did you mean to use *main.Foo?
    

    Take the following example

    type Foo struct{}
    
    func NewFoo() *Foo {
    	return &Foo{}
    }
    
    func (b *Foo) Hello() {
    	fmt.Println("hello")
    }
    
    type Fooer interface {
    	Hello()
    }
    
    func main() {
    	di := dig.New()
    	err := di.Provide(NewFoo)
    	if err != nil {
    		panic(err)
    	}
    	err = di.Invoke(func(f Fooer) {
    		fmt.Printf("f: %+v", f)
    	})
    	if err != nil {
    		panic(err)
    	}
    }
    

    So to make it work it needs to have a constructor function such as:

    func NewFoo() Fooer {
    	return &Foo{}
    }
    

    ~which is basically making us declare that Foo implements Fooer~ ~Would it be feasible to change the library so that it can workout itself if the struct implements the interface?~ [edit] as clarified in the comments this suggestion won't work

    Or alternatively, add a new ProvideOption which allow us to specify which concrete implementation to inject for a given interface?

  • Does not work with go.mod / vgo

    Does not work with go.mod / vgo

    Just import go.uber.org/dig to any go.mod enabled project and then run vgo mod -sync

    import "go.uber.org/dig" ->
    import "go.uber.org/dig/internal/digreflect" ->
    test ->
    import "go.uber.org/dig/internal/digreflect/tests/myrepository.git" ->
    import "mydependency": cannot find module providing package mydependency
    
  • Allow

    Allow "fan-in" for named types in dig graph

    I've been talking to @abhinav about this, In order to support use cases where a dig parameter depends on multiple inputs of the same type we need the ability to aggregate dig types together.

    So if we have the following outputs:

      Output1 MyType `name:"output1"`
      Output2 MyType `name:"output2"`
    

    I'd want to be able to grab all the "MyType"s in a single attribute.

    Solutions

    1: Add another tag to indicate that the type should be a fan-in collection:

    type In struct {
      dig.In
      Outputs map[string]MyType `collection:"true"` // tag name TBD
    }
    

    The string key in the Outputs variable will be the name of the attributes that were injected into the graph.

    2: Add a dig.Key (or similar) type for map keys. Any map of these types will be recognized as a fan-in collection.

    type In struct {
      dig.In
      Outputs map[dig.Key]MyType
    }
    

    The dig.Key would be a dig struct where we could embed information on the type. Currently that would only be the "name", but we could add more information later.

    Use cases

    YARPC Middleware

    Currently we don't have a good answer for middleware to ensure that we can take multiple middleware inputs and effectively construct a middleware graph without forcing the yarpcfx module to have a hard dependency on every middleware library (which gets out of control). With this system we'd be able to grab all middleware that was inserted into the graph. Since this is a map, the yarpcfx module would need to have an ordered list of middleware names it was expecting beforehand (all names should be optional) and it can construct the middleware chain itself. Of course this would only support names that yarpcfx explicitly expects, but that is necessary for the middleware ordering.

    YARPC Specs:

    The yarpc config options allow inserting custom Transport/PeerList/Updater specs into the yarpc config builder. Having support for this would allow us to detach the yarpc fx module from the implementations of each transport. For instance, a user could inject a "grpcfx" module into the graph which provided a "TransportSpec" for grpc that integrated seamlessly into the yarpc configuration.

  • Add SkipAcyclicVerification Option, and container.VerifyAcyclic

    Add SkipAcyclicVerification Option, and container.VerifyAcyclic

    It is not unreasonable for libraries using dig under the hood for dependency graph management to c.Provide constructors in a tight loop. Rather than paying the cost of of verifying the graph is acyclic for every Provide, this option and method combination can be used to verify the graph once, after the loop has completed.

  • [WIP] Sub graphs and Decorate

    [WIP] Sub graphs and Decorate

    uber-go/fx#653

    Also address #230

    Added support for creating child containers.

    • [x] Containers have access to all types provided using their parents (Invoke works anywhere)
    • [x] Containers have access to all types provided using their children (Invoke works anywhere)
    • [x] Provide checks the entire graph (all containers both up and down) for duplicates
    • [x] All success tests repeated for children
    • [x] Tests for multiple and multi level children
    • [x] Test for duplicate check in one of the children
    • [x] Stringer updated
  • dig.Param: Recurse into nested parameter objects

    dig.Param: Recurse into nested parameter objects

    This change adds support to parameter objects for recursing into fields that are also parameter objects. That is, this change allows the following,

    type OutputConfig struct {
        dig.Param
    
        Writer io.Writer
    }
    
    type Config struct {
        dig.Param
    
        Input io.Reader
        Output OutputConfig
    }
    
    func NewTransport(cfg Config) (*Transport, error) { .. }
    

    Besides the usefulness of treating fields similar to constructor parameters, there's another motivating use case for this: Aliasing dig.Param. Without this change, we have special handling for the dig.Param type, opting it out of resolution from dig. If a library author wants to use their own type in place of dig.Param (for example, fx.Param), they can't quite do this because any alias of dig.Param is a different type; one which the library does not special-case.

    package fx
    
    type Param dig.Param
    
    type Config struct {
        Param
    
        Input io.Reader
    }
    
    // The above with fail because dig doesn't know how to resolve fx.Param.
    

    With this change, Fx will be able to support the following.

    package fx
    
    type Param struct{ dig.Param }
    
    type Config struct {
        Param
    
        // ..
    }
    
  • Add dig.Optional for marking optional params

    Add dig.Optional for marking optional params

    Realized that fx can be improved so certain parameters provided, while in their absence, a default parameter value would be used.

    Add a new dig.Optional type that can be embedded in structs to mark that the dependency on them is optional.

  • [Prototype] Zero-value validation approach

    [Prototype] Zero-value validation approach

    Currently dig returns an error dependency of type is not registered if constructor argument fails to resolve during Invoke or Resolve. This change is introduced to resolve any absent arguments with zero value objects. Zero value objects are resolved during resolving constructor or invoking a function with arguments not yet present in the DIG container.

    When can it happen?

    1. Constructors are provided out of order
    2. Optional objects are not provided to the constructor

    What will be the expected behavior?

    1. No change in existing API on the container
    2. Invoke, resolving constructor never fails on missing constructor arguments in DIG container.
    3. Constructor is provided with zero value argument during call to continue execution
    4. Invoke/Resolve logs error message when zero value object is used
    5. Zero value object is never cached.
  • Invoke on provided/unprovided ctors

    Invoke on provided/unprovided ctors

    Calling Invoke on provided and unprovided funcs can result in executing constructors more than once and overwriting the graph with the resulted return objects. for provided constructors -

    ctor1(a *A, b *B) (x *x)
    ctor2() (a *A)
    

    Invoking constructors in order will result in ctor1 resolving *A and *B. Invoking ctor2 will result in resolving *A again.

  •  Combine Resolve, ResolveAll, and Invoke into a Locate func

    Combine Resolve, ResolveAll, and Invoke into a Locate func

    When you ask the container to resolve dependencies, that is called the "service locator" pattern.

    Combining Resolve, ResolveAll, and Invoke into a Locate func will streamline the experience:

    // locate 1 or more types
    var logger *zap.Logger
    var dispatcher *yarpc.Dispatcher
    container.Locate(&logger, &dispatcher)
    
    // same as above, using a func
    container.Locate(func(logger *zap.Logger, dispatcher *yarpc.Dispatcher) {
     
    })
    

    This has the benefit of:

    • Being more specific, giving a nod to the pattern actually being used here
    • Reduces API surface and simplifies using DIG
  • [2/2] Fix end-to-end behavior tests

    [2/2] Fix end-to-end behavior tests

    ☮️ 🙏 😇 🙇 I come in peace :bow:😇 🙏 ☮️

    See #70 for context.

    This PR follows up on the previous test-only diff. It removes all pre-existing tests, fixes the integration tests, and finally removes all features not required to make the end-to-end tests pass. Along the way, it does some fairly significant refactoring.

    Most importantly, it combines the internal graph package and the top-level dig package into a single package. Since Container and Graph are basically the same thing, this simplifies the code a fair bit without expanding the exported API at all. More importantly, it lets us improve overall code coverage with just the end-to-end tests:

    $ go test -cover .
    ok      go.uber.org/dig 0.010s  coverage: 91.1% of statements
    

    This gives us the freedom to refactor and add features aggressively, since we're only testing important user-facing APIs.

    Features removed (at least for now):

    • Container.Resolve: Fx doesn't need it and we don't want users interacting with dig directly, so it can go.
    • Container.Invoke: now only runs the supplied function. It doesn't provide any dependencies. (We can always add that back if necessary, but I like the clean separation between providing deps and triggering side effects.)

    Features added:

    • Consistent support for scalars, structs, functions (with caveats noted in the tests), and channels.

    All the end-to-end tests pass now.

  • dig

    dig "trace" mode

    Currently, we don't get any visibility into the types injected in the DI container of Dig. i.e. it's not really possible to see which constructors' provided types are the "most used" and where the "hot path"s are. Note that what I mean by "hot path" here isn't code that's executed frequently - each constructor in Dig is invoked precisely once. The "hot path" here is the constructor where the most of the graph depends on.

    Also this may be useful for identifying types that are provided but aren't really used anywhere, which may help users identify some dead code, or break down constructors that aren't used frequently, etc.

  • Allow dig.As with dig.Group

    Allow dig.As with dig.Group

    Hello there!

    Why I can't use dig.As with dig.Group provide option?

    It would be better if I can write:

    d.Provide(NewCleanService, dig.Group("cron_job"), dig.As(new(cron.Command)))
    

    instead of:

    d.Provide(NewCleanService)
    d.Provide(func(service *CleanService) cron.Command { return service }, dig.Group("cron_job")))
    
  • dig.In help

    dig.In help

    package main
    
    import (
    	"fmt"
    	"go.uber.org/dig"
    )
    
    type Animal interface {
    	Say()
    }
    
    type Dog struct {
    	Name string
    }
    
    // NewDog dig provider
    func NewDog() *Dog {
    	println("new dog")
    	return &Dog{
    		Name: "xiaohei",
    	}
    }
    
    func (d *Dog) Say() {
    	fmt.Printf("%s say\n", d.Name)
    }
    
    type Cat struct {
    	Name string
    }
    
    func (c *Cat) Say() {
    	fmt.Printf("%s say\n", c.Name)
    }
    
    // NewCat dig provider
    func NewCat() *Cat {
    	println("new cat")
    	return &Cat{
    		Name: "xiaohong",
    	}
    }
    
    type Zoo struct {
    	BlackDog *Dog
    	RedCat   *Cat
    }
    
    type injector struct {
    	dig.In
    	BlackDog *Dog `name:"dog"`
    	RedCat   *Cat `name:"cat"`
    }
    
    func NewZoo(inj injector) *Zoo {
    	println("new zoo")
    
    	return &Zoo{
    		BlackDog: inj.BlackDog,
    		RedCat:   inj.RedCat,
    	}
    }
    
    func main() {
    
    	container := dig.New()
    
    	container.Provide(NewDog, dig.Name("dog"))
    	container.Provide(NewCat, dig.Name("cat"))
    	container.Provide(NewZoo)
    
    	container.Invoke(func(z *Zoo) {
    		println("----")
    		z.RedCat.Say()
    	})
    
    }
    
    

    As above, I must create injector struct as param to NewZoo. How can I simplify it.Like this

    type Zoo struct {
    	dig.In
    	BlackDog *Dog `name:"dog"`
    	RedCat   *Cat `name:"cat"`
    }
    
    //type injector struct {
    //	dig.In
    //	BlackDog *Dog `name:"dog"`
    //	RedCat   *Cat `name:"cat"`
    //}
    
    func NewZoo(inj Zoo) *Zoo {
    	println("new zoo")
    
    	return &Zoo{
    		BlackDog: inj.BlackDog,
    		RedCat:   inj.RedCat,
    	}
    }
    
    
  • How to test dig container

    How to test dig container

    I am compelled to ask here but I am unable to find how to test the dig containers and services created by it. There is an unanswered stackoverflow question as well. https://stackoverflow.com/questions/71220974/how-to-test-uber-dig-application-golang

    Please point me to the right direction and some help please.

    Thanks.

  • Parallel container startup with deferred values

    Parallel container startup with deferred values

    Hi dig maintainers,

    My organization made an internal tool that has many different startup tasks that all produce a unique Go type. Before dig/fx, some tasks wrote to a shared struct, some tasks read from it, and some did both. This meant having to carefully order functions, keeping in mind these implicit dependencies hidden in func bodies. I'm busy removing this shared struct and rewriting each task as a dig/fx provider and letting dig order things automatically. It's wonderful! Can't thank you enough.

    However—and sorry for frontloading this so much—our existing code, poor quality as it is, does perform many slow tasks in parallel. Forcing these to happen in serial would push our execution time over our execution frequency. But dependency injection with dig is a perfect match with our codebase, so I would really like to work something out.

    I don't believe the core of dig is incompatible with parallel execution. To prove this to myself, as a first pass I made paramList use an Errgroup to call all its children and wait for them to finish, and I made the store maps sync.Map. Where two goroutines reached the same constructorNode, I put a mutex to protect the called field. It worked but felt too simplistic and hard to control.

    The approach I settled on lets all dig code run in one goroutine, and user-provided constructors can either run in the same goroutine (default) or in pooled/ephemeral goroutines. This keeps mutexes out of dig's data structures and lets users decide how much concurrency they want.

    I tried this several ways, but this pull request is the cleanest way I found. It creates a new deferred type params and constructorNodes return. A deferred can be observed and resolved like a very simple Promise. Since params and constructors pass values indirectly via a Scope, deferred doesn't need much state.

    I would very much like to get concurrent initialization into dig by any means; it doesn't have to be this pull request. I'm willing to any changes you deem necessary; let's work together!

    Refs GO-1191

An additive dependency injection container for Golang.

Alice Alice is an additive dependency injection container for Golang. Philosophy Design philosophy behind Alice: The application components should not

Oct 16, 2022
🛠 A full-featured dependency injection container for go programming language.

DI Dependency injection for Go programming language. Tutorial | Examples | Advanced features Dependency injection is one form of the broader technique

Dec 31, 2022
Go Dependency Injection Framework

Dingo Dependency injection for go Hello Dingo Dingo works very very similiar to Guice Basically one binds implementations/factories to interfaces, whi

Dec 25, 2022
Simple Dependency Injection Container
Simple Dependency Injection Container

?? gocontainer gocontainer - Dependency Injection Container ?? ABOUT Contributors: Rafał Lorenz Want to contribute ? Feel free to send pull requests!

Sep 27, 2022
Simple and yet powerful Dependency Injection for Go
Simple and yet powerful Dependency Injection for Go

goioc/di: Dependency Injection Why DI in Go? Why IoC at all? I've been using Dependency Injection in Java for nearly 10 years via Spring Framework. I'

Dec 28, 2022
Dependency Injection and Inversion of Control package

Linker Linker is Dependency Injection and Inversion of Control package. It supports the following features: Components registry Automatic dependency i

Sep 27, 2022
Strict Runtime Dependency Injection for Golang

wire Wire is runtime depedency injection/wiring for golang. It's designed to be strict to avoid your go application running without proper dependency

Sep 27, 2022
Compile-time dependency injection for Go

Dihedral Dihedral is a compile-time injection framework for Go. Getting started > go get -u github.com/dimes/dihedral Create a type you want injected

Jun 1, 2022
Compile-time Dependency Injection for Go

Wire: Automated Initialization in Go Wire is a code generation tool that automates connecting components using dependency injection. Dependencies betw

Jan 2, 2023
Generated dependency injection containers in go (golang)
Generated dependency injection containers in go (golang)

Generation of dependency injection containers for go programs (golang). Dingo is a code generator. It generates dependency injection containers based

Dec 22, 2022
A dependency injection library that is focused on clean API and flexibility

Dependency injection DI is a dependency injection library that is focused on clean API and flexibility. DI has two types of top-level abstractions: Co

Oct 13, 2022
golang-runtime-di is a framework for runtime dependency injection in go

golang-runtime-di description golang-runtime-di is a framework for runtime dependency injection in go. usage quickstart add it to your go.mod: go get

Aug 1, 2022
Golang PE injection on windows

GoPEInjection Golang PE injection on windows See: https://malwareunicorn.org/workshops/peinjection.html Based on Cryptowall's PE injection technique.

Jan 6, 2023
two scripts written in golang that will help you recognize dependency confusion.
two scripts written in golang that will help you recognize dependency confusion.

two scripts written in golang that will help you recognize dependency confusion.

Mar 3, 2022
Di - A (very) WIP Go 1.18+ generic dependency injection package based on type reflection

di A (very) WIP Go 1.18+ generic dependency injection package based on type refl

Apr 26, 2022
A dependency injection based application framework for Go.

?? Fx An application framework for Go that: Makes dependency injection easy. Eliminates the need for global state and func init(). Installation We rec

Jan 3, 2023
🦄🌈 YoyoGo is a simple, light and fast , dependency injection based micro-service framework written in Go.
🦄🌈 YoyoGo is a simple, light and fast , dependency injection based micro-service framework written in Go.

???? YoyoGo is a simple, light and fast , dependency injection based micro-service framework written in Go. Support Nacos ,Consoul ,Etcd ,Eureka ,kubernetes.

Jan 4, 2023
How we can run unit tests in parallel mode with failpoint injection taking effect and without injection race

This is a simple demo to show how we can run unit tests in parallel mode with failpoint injection taking effect and without injection race. The basic

Oct 31, 2021
hiboot is a high performance web and cli application framework with dependency injection support

Hiboot - web/cli application framework About Hiboot is a cloud native web and cli application framework written in Go. Hiboot is not trying to reinven

Nov 20, 2022
An additive dependency injection container for Golang.

Alice Alice is an additive dependency injection container for Golang. Philosophy Design philosophy behind Alice: The application components should not

Oct 16, 2022