ozzo-di

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() {
c := di.NewContainer()
c.RegisterAs(&Foo{"hello"}, di.InterfaceOf((*Bar)(nil)))
c.Call(test)
bar := c.Make(reflect.TypeOf(&MyBar{})).(Bar)
fmt.Println(bar.String())
}
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()
c.Register(&Foo{"hello"})
c.RegisterAs(&Foo{"hello"}, di.InterfaceOf((*Bar)(nil)))
c.RegisterAs(reflect.TypeOf(&Foo{}), di.InterfaceOf((*Bar)(nil)))
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:
type Composite struct {
Bar `inject:"true"`
}
composite := &Composite{}
c.Inject(composite)
func test(bar Bar) {
fmt.Println(bar.String())
}
c.Call(test)
foo := c.Make(reflect.TypeOf(&Foo{})).(*Foo)
bar := c.Make(di.InterfaceOf((*Bar)(nil))).(*Bar)
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.