Guice Style Dependency Injection Library for Golang
type AbstractModule interface {
Configure(binder *Binder)
}
Implement the AbstractModule
If a module has no dependency with other modules
type BillingModule struct {
}
func (r *BillingModule) Configure ( binder *di.Binder ) {
binder.BindSingleton((*TransactionLog)(nil), NewDBTransactionLog())
// or you can use Guice style binding code
binder.Bind((*TransactionLog)(nil)).ToInstance(NewDBTransactionLog());
}
If a module has dependencies with other modules
func (r *BillingModule) Configure ( binder *di.Binder ) {
provider := func(injector di.Injector) interface {} {
connection := injector.GetInstance((*Connection)(nil)).(Connection)
ret := NewDatabaseTransactionLog(connection)
return ret
}
binder.BindProvider((*TransactionLog)(nil), provider)
// or you can use Guice style binding code
binder.Bind((*TransactionLog)(nil)).ToProvider(provider);
}
binder.Bind((*TransactionLog)(nil)).ToProvider(provider).AsNonSingleton();
binder.Bind((*TransactionLog)(nil)).ToProvider(provider).AsEagerSingleton();
// NewDatabaseTransactionLog is constructor func
func NewDatabaseTransactionLog( connection DatabaseConnection ) DatabaseTransactionLog
// bind TransactionLog to construct func
binder.Bind((*TransactionLog)(nil)).ToConstructor(NewDatabaseTransactionLog);
// above Bind code is equivalent to below code
binder.BindProvider((*TransactionLog)(nil),func(injector di.Injector) interface{} {
return injector.InjectAndCall(NewDatabaseTransactionLog)
})
The Constructor function Should :
- Not Use Variadic Argument
- Returns Single return value
- Returns Pointer for struct type
package modules
import (
"github.com/csgura/di"
)
func GetImplements() *di.Implements {
impls := di.NewImplements()
impls.AddImplement("TestDB", &TestDBModule{})
impls.AddImplement("ControllerActor", &N32ControllerActorModule{})
impls.AddImplement("MemCache", &MemCacheModule{})
impls.AddImplement("LogrusLogger", &LogrusModule{})
return impls
}
You can create injector using CreateInjector method with AbstractModule list
injector := di.CreateInjector(&BillingModule{}, &OhterModule{})
Or you can create an Injector from implmentations with enabled module slice
cfg := hocon.New("application.conf")
// enabeld is []string type and it is list of name of modules should be configured
enabled := cfg.GetStringArray("modules")
impls := di.NewImplements()
// these are named module
impls.AddImplement("BillingModule", &BillingModule{})
impls.AddImplement("OtherModule", &OtherModule{})
// this is anonymous module. always configured
impls.AddBind(func(binder *di.Binder) {
binder.BindSingleton((*Config)(nil), cfg)
})
injector := impls.NewInjector(enabled)
Note : Config and hocon is not part of this Library
application.conf
looks like this
modules = [
"BillingModule",
]
log := injector.GetInstance((*TransactionLog)(nil)).(TransactionLog)
If you want to call Close() function of every singleton object that implements io.Closer and created by injector
list := injector.GetInstancesOf((*io.Closer)(nil))
for _, ins := range list {
c := ins.(io.Closer)
c.Close()
}
public class BillingModule extends AbstractModule {
protected void configure() {
bind(TransactionLog.class).toInstance(new DatabaseTransactionLog());
}
}
func (r *BillingModule) Configure ( binder *di.Binder ) {
binder.Bind((*TransactionLog)(nil)).ToInstance(NewDBTransactionLog());
}
public class BillingModule extends AbstractModule {
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class).in(Singleton.class);
}
}
Not Supported. Use Provider Binding or Constructor Binding
public class DatabaseTransactionLogProvider
implements Provider<TransactionLog> {
private final Connection connection;
@Inject
public DatabaseTransactionLogProvider(Connection connection) {
this.connection = connection;
}
public TransactionLog get() {
DatabaseTransactionLog transactionLog =
new DatabaseTransactionLog(connection);
return transactionLog;
}
}
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(TransactionLog.class).toProvider(DatabaseTransactionLogProvider.class);
}
func (r *BillingModule) Configure ( binder *di.Binder ) {
provider := func(injector di.Injector) interface {} {
connection := injector.GetInstance((*Connection)(nil)).(Connection)
ret := NewDatabaseTransactionLog(connection)
return ret
}
binder.Bind((*TransactionLog)(nil)).ToProvider(provider);
}
bind(TransactionLog.class)
.toConstructor(
DatabaseTransactionLog.class
.getConstructor(DatabaseConnection.class)
);
func NewDatabaseTransactionLog( connection DatabaseConnection ) DatabaseTransactionLog
binder.Bind((*TransactionLog)(nil)).ToConstructor(NewDatabaseTransactionLog);
- Singleton
bind(TransactionLog.class).to(DatabaseTransactionLog.class).in(Singleton.class);
- Eager singleton
bind(TransactionLog.class).to(InMemoryTransactionLog.class).asEagerSingleton();
- Non singleton ( default )
bind(TransactionLog.class).to(InMemoryTransactionLog.class)
- Singleton ( default )
binder.Bind((*TransactionLog)(nil)).ToProvider(provider);
- Eager singleton
binder.Bind((*TransactionLog)(nil)).ToProvider(provider).AsEagerSingleton();
- Non singleton ( not default )
binder.Bind((*TransactionLog)(nil)).ToProvider(provider).AsNonSingleton();
Injector injector = Guice.createInjector(new BillingModule(), new OtherModule(), ... );
injector := di.CreateInjector(&BillingModule{}, &OhterModule{})
injector.getBindings.forEach((key, value) => {
if (Scopes.isSingleton(value)) {
val obj = value.getProvider.get()
obj match {
case a: Closeable =>
a.close()
case _ =>
}
}
})
sorry. it is scala code
getBindings method not available, but GetInstancesOf method is available to iterate all singleton which assignable to the type
list := injector.GetInstancesOf((*io.Closer)(nil))
for _, ins := range list {
c := ins.(io.Closer)
c.Close()
}
class SomeClass {
@Inject var config : Config = _
}
val objref = new SomeClass()
injector.injectMembers( objref )
use di:"inject"
tag to inject member
type SomeClass struct {
config Config `di:"inject"`
}
obj := SomeClass{}
injector.InjectMembers(&obj)
bind(CreditCardProcessor.class)
.annotatedWith(PayPal.class)
.to(PayPalCreditCardProcessor.class);
bind(CreditCardProcessor.class)
.annotatedWith(Names.named("Checkout"))
.to(CheckoutCreditCardProcessor.class);
Not Supported. Use type definition
type CreditCardProcessor interface {}
type PayPal CreditCardProcessor
type Checkout CreditCardProcessor
binder.Bind((*PayPal)(nil)).ToProvider(NewPayPalCreditCardProcessor);
binder.Bind((*Checkout)(nil)).ToProvider(NewCheckoutCreditCardProcessor);
payPal := injector.GetInstance((*PayPal)(nil)).(CreditCardProcessor)
bind(MyConcreteClass.class);
bind(AnotherConcreteClass.class).in(Singleton.class);
Not Supported. Use Instance Binding or Provider Binding
binder.Bind((*MyConcreteClass)(nil).ToInstance(&MyConcreteClass{})
Not Supported
Module combined
= Modules.combine(new ProductionModule(), new TestModule());
combined := di.CombineModule(&ProductionModule{}, &TestModule{})
Module functionalTestModule
= Modules.override(new ProductionModule()).with(new TestModule());
functionalTestModule := di.OverrideModule(&ProductionModule{}).With(&TestModule{})