injector
is a reflect-based dependency injection library for Go.
- Registering and injecting dependencies by names
- Injecting dependencies by types
- Registering dependencies by factory functions
- Make sure Go is installed and add
injector
into your project by the following command:
go get github.com/bongnv/injector
- Import it to your code:
import "github.com/bongnv/injector"
- Create a new instance of
Injector
and start registering, injecting dependencies.
// ServiceAImpl is the example of an implementation.
type ServiceAImpl struct {}
// ServiceBImpl is another example of implementation that need to be injected.
type ServiceBImpl struct {
// Here you can notice that ServiceBImpl requests a dependency with the type of *ServiceAImpl.
ServiceA *ServiceAImpl `injector:"auto"`
}
func yourInitFunc() {
i := injector.New()
// add ServiceAImpl to the injector
i.Component(&ServiceAImpl{})
// create an instance of ServiceBImpl and inject its dependencies
b := &ServiceBImpl{}
i.Component(b)
}
injector
supports registering dependencies by factories with ComponentFromFactory
and NamedComponentFromFactory
. The given factory must implement the Factory
interface and the Create
will be invoked to create a new component.
Before the Create
method is invoked, injector
will inject dependencies to the given factory. After the Create
method is invoked, injector
will also inject dependencies to the created component.
// ServiceA has Logger as a dependency
type ServiceA struct {
Logger Logger `injector:"logger"`
}
type ServiceAFactory struct {
Config *AppConfig `injector:"config"`
}
// Create creates a new instance of ServiceA
func (f ServiceAFactory) Create() (interface{}, error) {
// logic to create A via Config
return &ServiceA{}, nil
}
// initialize dependencies
func initDependencies() {
i := injector.New()
// Register Logger and AppConfig
i.Component(&LoggerImpl{})
i.Component(&&AppConfig{})
// Create ServiceA via Factory, dependencies will be injected.
i.ComponentFromFactory(&ServiceAFactory{})
}
loadAppConfig
, newLogger
and newServiceA
are three factory functions to create different components. injector
allows loading dependencies as well as registering dependencies created by those functions.
func loadAppConfig() *AppConfig {
// load app config here
}
func newLogger(cfg *AppConfig) (Logger, error) {
// initialize a logger
return &loggerImpl{}
}
// ServiceA has Logger as a dependency
type ServiceA struct {
Logger Logger `injector:"logger"`
}
func newServiceA() (*ServiceA, error) {
// init your serviceA here
}
// init func
func initDependencies() {
i := injector.New()
i.ComponentFromFunc("config", loadAppConfig)
i.ComponentFromFunc("logger", newLogger),
// serviceA will be created and registered, logger will also be injected
i.Component(newServiceA),
}
As loggerImpl
satisfies the interface Logger
, it will be injected into ServiceA
automatically. If there are two dependencies that are eligible while injecting, an error will be returned. auto
is the keyword to indicate the type-based injection.
Component
can be used to register dependencies if names are not used to identifying the dependency.
// loggerImpl is an implementation that satisfies Logger interface.
type loggerImpl struct {}
// ServiceA has Logger as a dependency
type ServiceA struct {
Logger Logger `injector:"auto"`
}
// init func
func initDependencies() {
i := injector.New()
i.Component(&loggerImpl{}),
// serviceA will be registered, logger will also be injected by Logger type
i.Component(&ServiceA{}),
}