di

package module
v0.0.0-...-38d8525 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2016 License: MIT Imports: 2 Imported by: 0

README

ozzo-di

GoDoc Build Status Coverage Status Go Report

Other Languages

Description

ozzo-di is a dependency injection (DI) container in Go language. It has the following features:

  • DI via concrete types, interfaces, and provider functions
  • DI of function parameter values and struct fields
  • Creating and injecting new objects
  • Hierarchical DI containers

Requirements

Go 1.2 or above.

Installation

Run the following command to install the package:

go get github.com/go-ozzo/ozzo-di

Getting Started

The following code snippet shows how you can use the DI container.

package main

import (
	"fmt"
	"reflect"
	"github.com/go-ozzo/ozzo-di"
)

type Bar interface {
    String() string
}

func test(bar Bar) {
    fmt.Println(bar.String())
}

type Foo struct {
    s string
}

func (f *Foo) String() string {
    return f.s
}

type MyBar struct {
    Bar `inject`
}

func main() {
    // creating a DI container
	c := di.NewContainer()

    // register a Foo instance as the Bar interface type
    c.RegisterAs(&Foo{"hello"}, di.InterfaceOf((*Bar)(nil)))

    // &Foo{"hello"} will be injected as the Bar parameter for test()
    c.Call(test)
    // Output:
    // hello

    // create a MyBar object and inject its Bar field
    bar := c.Make(reflect.TypeOf(&MyBar{})).(Bar)
    fmt.Println(bar.String())
    // Output:
    // hello
}

Type Registration

di.Container is a DI container that relies on types to determine what values should be used for injection. In order for this to happen, you usually should register the types that need DI support. di.Container supports three kinds of type registration, as shown in the following code snippet:

c := di.NewContainer()

// 1. registering a concrete type:

// &Foo{"hello"} is registered as the corresponding concrete type (*Foo)
c.Register(&Foo{"hello"})


// 2. registering an interface:

// &Foo{"hello"} is registered as the Bar interface
c.RegisterAs(&Foo{"hello"}, di.InterfaceOf((*Bar)(nil)))
// concrete type (*Foo) is registered as the Bar interface
c.RegisterAs(reflect.TypeOf(&Foo{}), di.InterfaceOf((*Bar)(nil)))


// 3. registering a provider:

// a provider function is registered as the Bar interface.
// The provider function will be called when injecting Bar.
c.RegisterProvider(func(di.Container) interface{} {
    return &Foo{"hello"}
}, di.InterfaceOf((*Bar)(nil)), true)

Tip: To specify an interface type during registration, use the helper function di.InterfaceOf((*InterfaceName)(nil)). For concrete types, use go reflection function reflect.TypeOf(TypeName{}).

Value Injection

di.Container supports three types of value injection, as shown in the following code snippet:

// ...following the previous registration example...

type Composite struct {
    Bar `inject:"true"`
}

// 1. struct field injection:

// Exported struct field tagged with `inject` and anonymous fields will be injected with values.
// Here Composite.Bar will be injected with &Foo{"hello"}
composite := &Composite{}
c.Inject(composite)


// 2. function parameter injection:

// Function parameters will be injected with values according to their types.
// Here bar will be injected with &Foo{"hello"}
func test(bar Bar) {
    fmt.Println(bar.String())
}
c.Call(test)


// 3. making new instances:
// New struct instances can be created with their fields injected.
// Or a singleton instance may be returned.

foo := c.Make(reflect.TypeOf(&Foo{})).(*Foo)          // returns the singleton &Foo{"hello"}
bar := c.Make(di.InterfaceOf((*Bar)(nil))).(*Bar)     // returns the singleton &Foo{"hello"}

// returns a new Composite instance with Bar injected with the singleton &Foo{"hello"}
composite := c.Make(reflect.TypeOf(&Composite{})).(*Composite)

When injecting a previously registered type, if a value is already registered as that type, the value itself will be used for injection.

If a provider is registered as a type, the provider will be called whose result will be used for injection. While registering a provider, you may use the third parameter for Container.RegisterProvider() to indicate whether the provider should be called every time the injection is needed or only the first time. If the latter, the provider will only be called once and the same return result will be used for injection of the corresponding registered type.

When injecting a value for a type T that has not been registered, the following strategy will be taken:

  • If *T has been registered, the corresponding value will be dereferenced and returned;
  • If T is a pointer type of P, the pointer to the value injected for P will be returned;
  • If T is a struct type, a new instance will be created and its fields will be injected;
  • If T is Slice, Map, or Chan, a new instance will be created and initialized;
  • For all other cases, a zero value will be returned.

Credits

ozzo-di has referenced the implementation of codegansta/inject.

Documentation

Overview

Package di implements a dependency injection (DI) container.

Example
package main

import (
	"fmt"
	"reflect"

	"github.com/go-ozzo/ozzo-di"
)

type Bar interface {
	String() string
}

func test(bar Bar) {
	fmt.Println(bar.String())
}

type Foo struct {
	s string
}

func (f *Foo) String() string {
	return f.s
}

type MyBar struct {
	Bar `inject:"true"`
}

func main() {
	// creating a DI container
	c := di.NewContainer()

	// register a Foo instance as the Bar interface type
	c.RegisterAs(&Foo{"hello"}, di.InterfaceOf((*Bar)(nil)))

	// &Foo{"hello"} will be injected as the Bar parameter for test()
	c.Call(test)

	// create a MyBar object and inject its Bar field
	bar := c.Make(reflect.TypeOf(&MyBar{})).(Bar)
	fmt.Println(bar.String() + "2")

}
Output:

hello
hello2

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func InterfaceOf

func InterfaceOf(iface interface{}) reflect.Type

InterfaceOf is a helper method for turning an interface pointer into an interface reflection type. It is often used when calling RegisterAs() or Make() where you may want to specify an interface type. For example,

c := di.NewContainer()
c.RegisterAs(Foo{}, di.InterfaceOf((*Bar)(nil)))
foo := di.Make(di.InterfaceOf((*Bar)(nil)))

Types

type Container

type Container interface {
	// ParentContainer returns the parent container, if any.
	ParentContainer() Container
	// SetParentContainer sets the parent container.
	SetParentContainer(Container)

	// HasRegistered returns a value indicating whether the specified type has been registered before.
	HasRegistered(reflect.Type) bool
	// Unregister removes the specified type registration from the container
	Unregister(reflect.Type)

	// Register registers the specified value and associates it with the type of the value.
	Register(interface{})
	// RegisterAs registers the specified value or type, and associates it with the specified type.
	// For example,
	//
	//   c := di.NewContainer()
	//   // register a Foo struct as the Bar interface
	//   c.RegisterAs(&Foo{"abc"}, di.InterfaceOf((*Bar)(nil)))
	//   // register the Foo type as the Bar interface
	//   c.RegisterAs(reflect.TypeOf(&Foo{}), di.InterfaceOf((*Bar)(nil)))
	RegisterAs(interface{}, reflect.Type)
	// RegisterProvider registers the provider and associates it with the specified type.
	// When injecting or making a value for the type, the provider will be called and
	// its return value will be used as the value of the requested type. If shared is true,
	// the provider will only be called once, and its return value will be kept and used for
	// every injection request.
	RegisterProvider(p Provider, t reflect.Type, shared bool)

	// Call calls the specified function/method by injecting all its parameters.
	// The function/method result is returned as a slice.
	Call(interface{}) []interface{}
	// Inject injects the exported fields tagged with "inject" of the given struct.
	// Note that the struct should be passed as a pointer, or the fields won't be injected.
	Inject(interface{})
	// Make returns an instance of the specified type. If the instance is a newly created struct, its fields
	// will be injected by calling Inject(). Note that Make does not always create a new instance. If the type
	// has been registered and is associated with a value, that value will be returned.
	Make(reflect.Type) interface{}
}

Container is a dependency injection (DI) container based on type mapping.

Using Container involves two steps. First, register values, types, or providers with the types that should allow DI. Second, use one of the DI methods to achieve DI. For example,

import (
    "reflect"
    "github.com/go-ozzo/ozzo-di"
)

c := di.NewContainer()

// Step 1: register values, types, providers

// register the value Foo{"abc"} as type Foo
c.Register(Foo{"abc"})
// register the value Foo{"abc"} as the interface Bar
c.RegisterAs(Foo{"abc"}, di.InterfaceOf((*Bar)(nil)))
// register the struct Foo as the interface Bar
c.RegisterAs(reflect.TypeOf(Foo{}), di.InterfaceOf((*Bar)(nil)))
// register a provider that returns a shared value as the interface Bar
c.RegisterProvider(func(Container) reflect.Value {
    return reflect.ValueOf(&Foo{"xyz"})
}, di.InterfaceOf((*Bar)(nil)), true)

// Step 2: dependency injection

// use `inject` tag to indicate which fields can be injected
type Tee struct {
        Foo `inject`
    bar Bar `inject`
}
// inject the fields of a struct
t := Tee{}
c.Inject(&t)
// inject function parameters
c.Call(func(bar Bar, foo Foo) {...})
// build a value of the specified type with injection
t2 := c.Build(reflect.TypeOf(&Tee{})).(*Tee)

Note that when building an unregistered type, zero value will be returned. If the type is a struct, the zero value will be further injected by Inject() for those fields tagged with "inject".

func NewContainer

func NewContainer() Container

NewContainer creates a new Dependency Injection (DI) container.

type Provider

type Provider func(Container) reflect.Value

Provider is a function for creating a new instance of the associated type.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL