🛠 A full-featured dependency injection container for go programming language.

DI

Documentation Release Build Status Go Report Card Code Coverage

Dependency injection for Go programming language.

Tutorial | Examples | Advanced features

Dependency injection is one form of the broader technique of inversion of control. It is used to increase modularity of the program and make it extensible.

This library helps you to organize responsibilities in your codebase and make it easy to combine low-level implementation into high-level behavior without boilerplate.

Features

  • Intuitive auto wiring
  • Interface implementations
  • Constructor injection
  • Optional injection
  • Field injection
  • Lazy-loading
  • Tagging
  • Grouping
  • Cleanup

Documentation

You can use standard pkg.go.dev and inline code comments. If you do not have experience with auto-wiring libraries as google/wire, uber-go/dig or another - start with tutorial.

Install

go get github.com/goava/di

What it looks like

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/goava/di"
)

func main() {
	di.SetTracer(&di.StdTracer{})
	// create container
	c, err := di.New(
		di.Provide(NewContext),  // provide application context
		di.Provide(NewServer),   // provide http server
		di.Provide(NewServeMux), // provide http serve mux
		// controllers as []Controller group
		di.Provide(NewOrderController, di.As(new(Controller))),
		di.Provide(NewUserController, di.As(new(Controller))),
	)
	// handle container errors
	if err != nil {
		log.Fatal(err)
	}
	// invoke function
	if err := c.Invoke(StartServer); err != nil {
		log.Fatal(err)
	}
}

Full code available here.

Questions

If you have any questions, feel free to create an issue.

Comments
  • How to build a service conditionally?

    How to build a service conditionally?

    Hello.

    I'm considering introducing DI into my project. Your DI implementation container looks good enough :) But I have a question: how to create services that are created through user's configuration? Here's an example:

    package main
    
    import (
    	"github.com/goava/di"
    	"github.com/spf13/viper"
    )
    
    type ServiceInterface interface {
    	Do()
    }
    
    type DependencyA interface {}
    type ServiceImplementationA struct {DependencyA}
    func (s *ServiceImplementationA) Do() {}
    
    type DependencyB interface {}
    type ServiceImplementationB struct {DependencyB}
    func (s *ServiceImplementationB) Do() {}
    
    func NewService(config *viper.Viper) ServiceInterface {
    	if viper.GetString("preferred_service") == "B" {
    		// Resolve as ServiceImplementationB
    	}
    
    	// Otherwise resolve as ServiceImplementationA
    }
    
    func main() {
    	container, _ := di.New(
    		di.Provide(viper.New),
    		di.Provide(NewService),
    	)
    	var service ServiceInterface
    	container.Resolve(&service)
    }
    

    Depending on the configuration, I want to create a service interface implementation. But each implementation has its own dependencies list (I have not provided them manually in the example). I need a way to somehow call container.Resolve(&concreteImplementation) from the NewService function.

    Is there any way to do this? Or maybe I just misunderstand how it should be done at all?

  • Unable to make interfaces group by using the same funtion interface implenentations

    Unable to make interfaces group by using the same funtion interface implenentations

    The title :) https://play.golang.org/p/ZvWhZaxyzM6

    package main
    
    import (
    	"context"
    	"log"
    
    	"github.com/goava/di"
    )
    
    type Interface interface {
    	Do(ctx context.Context) error
    }
    
    type FuncInterface func(ctx context.Context) error
    func (c FuncInterface) Do(ctx context.Context) error {
    	return c(ctx)
    }
    
    func createFirst() FuncInterface {
    	return func(ctx context.Context) error {
    		return nil
    	}
    }
    
    func createSecond() FuncInterface {
    	return func(ctx context.Context) error {
    		return nil
    	}
    }
    
    func main() {
    	container, err := di.New(
    		di.Provide(createFirst, di.As(new(Interface))),
    		di.Provide(createSecond, di.As(new(Interface))),
    	)
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	var interfaces []Interface
    	err = container.Resolve(&interfaces)
    	if err != nil {
    		log.Fatal(err)
    	}
    }
    

    The error:

    main.FuncInterface already exists in dependency graph
    
  • Add support for di. Inject in  Invoke()

    Add support for di. Inject in Invoke()

    Actually, the title. I've prepared an example that shows the problem: https://play.golang.org/p/vZ2JvfmvJBB

    package main
    
    import (
    	"log"
    
    	"github.com/goava/di"
    )
    
    type Dependency struct {}
    
    func NewDependency() *Dependency {
    	return &Dependency{}
    }
    
    type Params struct {
    	di.Inject
    
    	Dependency *Dependency `di:""`
    }
    
    func InvokeWithDependencyAsParam(params Params) {
    	// Some code
    }
    
    func main() {
    	_, err := di.New(
    		di.Provide(NewDependency),
    		di.Invoke(InvokeWithDependencyAsParam),
    	)
    	if err != nil {
    		log.Fatal(err)
    	}
    }
    
  • Allow decorating of services in the container

    Allow decorating of services in the container

    I started to try to implement this but I dont really understand how the internals are working right now. My Idea was to add another Option to di which is called Decorate.

    package main
    
    import (
    	"fmt"
    
    	"github.com/goava/di"
    )
    
    func main() {
    	container, err := di.New(
    		di.Provide(NewExample),
    	)
    	if err != nil {
    		panic(err)
    	}
    	
    	container.Invoke(func(e Example) {
    		fmt.Println(e) // Will print "Example"
    	})
    
           err = container.Decorate(DecorateExample)
           if err != nil {
    		panic(err)
    	}
    
    	container.Invoke(func(e Example) {
    		fmt.Println(e) // Will print "Example is now Decorated"
    	})
    }
    
    type Example string
    
    func NewExample() Example {
    	return "Example"
    }
    
    func DecorateExample(e Example) Example {
    	return e + " is now Decorated"
    }
    

    This can also be expaned to have options like priority to allow ordered decorations. Of course this only works when the decorated type isnt used before decoration. So you would have to call Decorate before Invoking anything.

  • Using `di.WithName()` breaks when having one entry without a `di.Name()`

    Using `di.WithName()` breaks when having one entry without a `di.Name()`

    When I provide the Container with multiple implementations of an Object and have one that doesnt have a Name the container doesnt know how to resolve it properly and returns an error when resolving a named entry

  • Add a Application Start and Stop System

    Add a Application Start and Stop System

    I am currently using uber-go/fx and I want to switch to DI, but sadly DI is missing a core feature to not run the invokes in compile state, instead having a Start() and Stop() function to kick off the Invokes and run until a control signal got sent, like CTRL+C.

    	container := di.New(
    // options
    	)
    
    	startCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
    	defer cancel()
    	if err := container.Start(startCtx); err != nil {
    		log.Fatal(err)
    	}
    
           <- container.Done()
    
    	stopCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
    	defer cancel()
    	if err := container.Stop(stopCtx); err != nil {
    		log.Fatal(err)
    	}
    

    or less verbose if someone doesnt need full controll over the start and stop system

    	container := di.New(
    // options
    	)
    
             container.Run()
    
  • concurrent map read and map write

    concurrent map read and map write

    When calling "Invoke" function in multiple goroutine, it can lead to concurrent read and map write in this part of the code :

    // check cycle verified
    if !c.verified[param.Key()] {
    	err := checkCycles(c, param)
    	if err != nil {
    		return err
    	}
    	c.verified[param.Key()] = true
    }
    
  • Implement injectable struct.

    Implement injectable struct.

    Closes #2. Implements #5. @zeromake try this branch. I rework a struct field injection mechanism. Tags support with embedded di.Injectable or di.Parameter(for backward compatibility).

    package main
    
    import (
    	"net/http"
    
    	"github.com/goava/di"
    )
    
    type Application struct {
    	di.Injectable
    	Server *http.Server   `di:""`
    	Mux    *http.ServeMux `di:""`
    }
    
    func New() *Application {
    	return &Application{}
    }
    
    func main() {
    	var app *Application
    	_, err := di.New(
    		di.Provide(func() *http.Server { return &http.Server{} }),
    		di.Provide(http.NewServeMux),
    		di.Provide(New),
    		di.Resolve(&app),
    	)
    	if err != nil {
    		panic(err)
    	}
    	if app.Server == nil {
    		panic("server not found")
    	}
    	if app.Mux == nil {
    		panic("mux not found")
    	}
    }
    
  • Add Late Provides

    Add Late Provides

    I am currently using a patched version of uber-go/fx and uber-go/dig where I already added these Features. It allows to execute code and add more options based on things that are in the Container.

    type Configuration struct {
     	 Enabled bool
    }
    
    di.New(
    di.Provide(func () *Configuration {
    		return &Configuration{ true }
    }),
    di.Provide(func(configuration *Configuration) di.Option {
    	if configuration.Enabled {
    		return di.Invoke(func () { fmt.Println("Hello World") })
    	}
    		return nil
    })
    )
    
  • Change how Injected structs are tagged

    Change how Injected structs are tagged

    Currently injected structs resolve using tag constraint like so:

    type Parameters struct {
    	di.Inject
    	
    	// use tag for the container to know that field need to be injected.
    	Leader   *DatabaseConfig `type:"leader"`
    	Follower *DatabaseConfig `type:"follower"`
    }
    

    But things start to break down if that same struct is used in other ways, for example marshalling:

    type Parameters struct {
    	di.Inject
    	
    	// use tag for the container to know that field need to be injected.
    	Leader   *DatabaseConfig `type:"leader"   json:"leader"`
    	Follower *DatabaseConfig `type:"follower" json:"follower"`
    }
    

    To avoid conflicting with other libs that also use tags to provide features on structs, I propose that we change how goava/di looks for struct tags that look like this instead:

    type Parameters struct {
    	di.Inject
    	
    	// use tag for the container to know that field need to be injected.
    	Leader   *DatabaseConfig `di:"type=leader"`
    	Follower *DatabaseConfig `di:"type=follower"`
    }
    
    
    
  • Tags

    Tags

    Implement tag system

    Tags are embedded expanders for injecting type. Embed it in your injecting type:

    type Command interface {
      // ...
    }
    
    type ListConsoleCommand struct {
      di.Tags `console.command:"list"`
    }
    
    func NewListConsoleCommand() {
      return &ListConsoleCommand{}
    }
    

    Provide your type as interface:

    c, err := di.New(
       di.Provide(NewListConsoleCommand, di.As(new(Command)))
       // or
       di.Provide(NewListConsoleCommandWithoutTags, di.As(new(Command)), di.WithTag("console.command", "list"))
    )
    

    And use Resolve() with WithTag() option for fetch instance with concrete tag-value combination:

     var command Command
     container.Resolve(&command, WithTag("console.command", "list"))
    
  • Possibility to disable singleton behavior.

    Possibility to disable singleton behavior.

    Does it possible to disable singleton behavior for some dependencies? Probably some ResolveOption or ProvideOption for that.

    For example I want use goava/di container for testing with mocks. I have two different setups:

    • di.New(...) with production implementation of interfaces which is used for release builds.
    • di.New(...) with mocks which replace external APIs implementations.

    Majority of mock libs assumes that each test recreate mock object but di container always returns same instance of mock object. I can call di.New for each test case but it is not looks good.

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
A reflection based dependency injection toolkit for Go.

⚒️ dig A reflection based dependency injection toolkit for Go. Good for: Powering an application framework, e.g. Fx. Resolving the object graph during

Jan 1, 2023
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
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
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
A lightweight yet powerful IoC container for Go projects

Container A lightweight yet powerful IoC container for Go projects. It provides a simple, fluent and easy-to-use interface to make dependency injectio

Dec 29, 2022
Serverless Container Workflows
Serverless Container Workflows

direktiv event-based serverless container workflows Check out our online demo: wf.direktiv.io What is Direktiv? Direktiv is a specification for a serv

Dec 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
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
[deprecated] A full-featured SPDY library for the Go language.

Deprecated With the release of Go1.6 and the addition of http2 to the standard library, this package is no longer under active development. It is high

Oct 1, 2022
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