@@ -45,6 +45,20 @@ the management of object lifetimes and the inversion of control in your applicat
4545
4646- ** Concurrency-Safe** : Utilizes a mutex to ensure safe concurrent access to the container.
4747
48+
49+ - ** Placeholder Service Registration** : Designed to simplify scenarios where certain dependencies cannot be resolved at the time of service registration but can be resolved later during runtime.
50+
51+
52+ - ** Isolated Containers** : Enables the creation of multiple isolated, modular containers to support more scalable and testable architectures, especially for Modular Monoliths.
53+
54+
55+ - ** Aliases** : A powerful way to register type mappings, allowing one type to be treated as another, typically an interface or a more abstract type.
56+
57+
58+ - ** Runtime Validation** : Allow for better error handling and validation during the startup or testing phases of an application (circular dependencies, lifetime misalignment, and missing dependencies).
59+
60+
61+ - ** Graceful Termination** : To ensure graceful application (or context) termination and proper cleanup of resources, including shutting down all resolved objects created during the application (or context) lifetime.
4862<br />
4963
5064## Installation
@@ -99,7 +113,7 @@ var c Counter
99113c = &models.SimpleCounter {}
100114
101115// register
102- ore.RegisterEagerSingleton [Counter](c)
116+ ore.RegisterSingleton [Counter](c)
103117
104118ctx := context.Background ()
105119
@@ -115,11 +129,11 @@ c.AddOne()
115129
116130``` go
117131// register
118- ore.RegisterLazyCreator [Counter](ore.Scoped , &models.SimpleCounter {})
132+ ore.RegisterCreator [Counter](ore.Scoped , &models.SimpleCounter {})
119133
120134// OR
121- // ore.RegisterLazyCreator [Counter](ore.Transient, &models.SimpleCounter{})
122- // ore.RegisterLazyCreator [Counter](ore.Singleton, &models.SimpleCounter{})
135+ // ore.RegisterCreator [Counter](ore.Transient, &models.SimpleCounter{})
136+ // ore.RegisterCreator [Counter](ore.Singleton, &models.SimpleCounter{})
123137
124138ctx := context.Background ()
125139
@@ -142,29 +156,30 @@ fmt.Println("TOTAL: ", c.GetCount())
142156
143157``` go
144158 // register
145- ore.RegisterLazyFunc [Counter](ore.Scoped , func (ctx context.Context ) (Counter, context.Context ) {
159+ ore.RegisterFunc [Counter](ore.Scoped , func (ctx context.Context ) (Counter, context.Context ) {
146160 return &models.SimpleCounter {}, ctx
147161})
148162
149163// OR
150- // ore.RegisterLazyFunc [Counter](ore.Transient, func(ctx context.Context) (Counter, context.Context) {
164+ // ore.RegisterFunc [Counter](ore.Transient, func(ctx context.Context) (Counter, context.Context) {
151165// return &models.SimpleCounter{}, ctx
152166// })
153167
154168// Keyed service registration
155- // ore.RegisterLazyFunc [Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) {
169+ // ore.RegisterKeyedFunc [Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) {
156170// return &models.SimpleCounter{}, ctx
157- // }, "name here", 1234 )
171+ // }, "key- here")
158172
159173ctx := context.Background ()
160174
161175// retrieve
162176c , ctx := ore.Get [Counter](ctx)
177+
163178c.AddOne ()
164179c.AddOne ()
165180
166181// Keyed service retrieval
167- // c, ctx := ore.Get [Counter](ctx, "name here", 1234 )
182+ // c, ctx := ore.GetKeyed [Counter](ctx, "key- here")
168183
169184// retrieve again
170185c, ctx = ore.Get [Counter](ctx)
@@ -180,15 +195,15 @@ fmt.Println("TOTAL: ", c.GetCount())
180195
181196``` go
182197 // register
183- ore.RegisterLazyCreator [Counter](ore.Scoped , &models.SimpleCounter {})
198+ ore.RegisterCreator [Counter](ore.Scoped , &models.SimpleCounter {})
184199
185- ore.RegisterLazyCreator [Counter](ore.Scoped , &yetAnotherCounter{})
200+ ore.RegisterCreator [Counter](ore.Scoped , &yetAnotherCounter{})
186201
187- ore.RegisterLazyFunc [Counter](ore.Transient , func (ctx context.Context ) (Counter, context.Context ) {
202+ ore.RegisterFunc [Counter](ore.Transient , func (ctx context.Context ) (Counter, context.Context ) {
188203 return &models.SimpleCounter {}, ctx
189204})
190205
191- ore.RegisterLazyCreator [Counter](ore.Singleton , &yetAnotherCounter{})
206+ ore.RegisterCreator [Counter](ore.Singleton , &yetAnotherCounter{})
192207
193208ctx := context.Background ()
194209
@@ -217,18 +232,18 @@ The last registered implementation takes precedence, so you can register a mock
217232
218233``` go
219234 // register
220- ore.RegisterLazyFunc [Counter](ore.Singleton , func (ctx context.Context ) (Counter, context.Context ) {
235+ ore.RegisterKeyedFunc [Counter](ore.Singleton , func (ctx context.Context ) (Counter, context.Context ) {
221236 return &models.SimpleCounter {}, ctx
222- }, " name here" , 1234 )
237+ }, " key- here" )
223238
224- // ore.RegisterLazyCreator [Counter](ore.Scoped, &models.SimpleCounter{}, "name here", 1234 )
239+ // ore.RegisterKeyedCreator [Counter](ore.Scoped, &models.SimpleCounter{}, "key- here")
225240
226- // ore.RegisterEagerSingleton [Counter](&models.SimpleCounter{}, "name here", 1234 )
241+ // ore.RegisterKeyedSingleton [Counter](&models.SimpleCounter{}, "key- here")
227242
228243ctx := context.Background ()
229244
230245// Keyed service retrieval
231- c , ctx := ore.Get [Counter](ctx, " name here" , 1234 )
246+ c , ctx := ore.GetKeyed [Counter](ctx, " key- here" )
232247c.AddOne ()
233248
234249// prints out: `TOTAL: 1`
@@ -249,13 +264,13 @@ type Trader struct {
249264} // implements IPerson
250265
251266func TestGetInterfaceAlias (t *testing .T ) {
252- ore.RegisterLazyFunc (ore.Scoped , func (ctx context.Context ) (*Broker, context.Context ) {
267+ ore.RegisterFunc (ore.Scoped , func (ctx context.Context ) (*Broker, context.Context ) {
253268 return &Broker{Name: " Peter" }, ctx
254269 })
255- ore.RegisterLazyFunc (ore.Scoped , func (ctx context.Context ) (*Broker, context.Context ) {
270+ ore.RegisterFunc (ore.Scoped , func (ctx context.Context ) (*Broker, context.Context ) {
256271 return &Broker{Name: " John" }, ctx
257272 })
258- ore.RegisterLazyFunc (ore.Scoped , func (ctx context.Context ) (*Trader, context.Context ) {
273+ ore.RegisterFunc (ore.Scoped , func (ctx context.Context ) (*Trader, context.Context ) {
259274 return &Trader{Name: " Mary" }, ctx
260275 })
261276
@@ -321,9 +336,9 @@ Here how Ore can help you:
321336type Shutdowner interface {
322337 Shutdown ()
323338}
324- ore.RegisterEagerSingleton (&Logger{}) // *Logger implements Shutdowner
325- ore.RegisterEagerSingleton (&SomeRepository{}) // *SomeRepository implements Shutdowner
326- ore.RegisterEagerSingleton (&SomeService{}, " some_module" ) // *SomeService implements Shutdowner
339+ ore.RegisterSingleton (&Logger{}) // *Logger implements Shutdowner
340+ ore.RegisterSingleton (&SomeRepository{}) // *SomeRepository implements Shutdowner
341+ ore.RegisterKeyedSingleton (&SomeService{}, " some_module" ) // *SomeService implements Shutdowner
327342
328343// On application termination, Ore can help to retrieve all the singletons implementation
329344// of the `Shutdowner` interface.
@@ -360,7 +375,7 @@ Here how Ore can help you:
360375type Disposer interface {
361376 Dispose ()
362377}
363- ore.RegisterLazyCreator (ore.Scoped , &SomeDisposableService{}) // *SomeDisposableService implements Disposer
378+ ore.RegisterCreator (ore.Scoped , &SomeDisposableService{}) // *SomeDisposableService implements Disposer
364379
365380// a new request arrive
366381ctx , cancel := context.WithCancel (context.Background ())
@@ -392,24 +407,24 @@ The `ore.GetResolvedScopedInstances[TInterface](context)` function returns a lis
392407
393408### Multiple Containers (a.k.a Modules)
394409
395- | DefaultContainer | Custom container |
396- | ------------------| ------------------|
397- | Get | GetFromContainer |
398- | GetList | GetListFromContainer |
410+ | DefaultContainer | Custom container |
411+ | ----------------------- | ------------------ ------------------|
412+ | Get | GetFromContainer |
413+ | GetList | GetListFromContainer |
399414| GetResolvedSingletons | GetResolvedSingletonsFromContainer |
400- | RegisterAlias | RegisterAliasToContainer |
401- | RegisterEagerSingleton | RegisterEagerSingletonToContainer |
402- | RegisterLazyCreator | RegisterLazyCreatorToContainer |
403- | RegisterLazyFunc | RegisterLazyFuncToContainer |
404- | RegisterPlaceHolder | RegisterPlaceHolderToContainer |
405- | ProvideScopedValue | ProvideScopedValueToContainer |
415+ | RegisterAlias | RegisterAliasToContainer |
416+ | RegisterSingleton | RegisterSingletonToContainer |
417+ | RegisterCreator | RegisterCreatorToContainer |
418+ | RegisterFunc | RegisterFuncToContainer |
419+ | RegisterPlaceholder | RegisterPlaceholderToContainer |
420+ | ProvideScopedValue | ProvideScopedValueToContainer |
406421
407422Most of time you only need the Default Container. In rare use case such as the Modular Monolith Architecture, you might want to use multiple containers, one per module. Ore provides minimum support for "module" in this case:
408423
409424``` go
410425// broker module
411426brokerContainer := ore.NewContainer ()
412- ore.RegisterLazyFuncToContainer (brokerContainer, ore.Singleton , func (ctx context.Context ) (*Broker, context.Context ) {
427+ ore.RegisterFuncToContainer (brokerContainer, ore.Singleton , func (ctx context.Context ) (*Broker, context.Context ) {
413428 brs, ctx = ore.GetFromContainer [*BrokerageSystem](brokerContainer, ctx)
414429 return &Broker{brs}, ctx
415430})
@@ -420,7 +435,7 @@ broker, _ := ore.GetFromContainer[*Broker](brokerContainer, context.Background()
420435
421436// trader module
422437traderContainer := ore.NewContainer ()
423- ore.RegisterLazyFuncToContainer (traderContainer, ore.Singleton , func (ctx context.Context ) (*Trader, context.Context ) {
438+ ore.RegisterFuncToContainer (traderContainer, ore.Singleton , func (ctx context.Context ) (*Trader, context.Context ) {
424439 mkp, ctx = ore.GetFromContainer [*MarketPlace](traderContainer, ctx)
425440 return &Trader{mkp}, ctx
426441})
@@ -438,14 +453,14 @@ A common scenario is that your "Service" depends on something which you couldn't
438453
439454``` go
440455// register SomeService which depends on "someConfig"
441- ore.RegisterLazyFunc [*SomeService](ore.Scoped , func (ctx context.Context ) (*SomeService, context.Context ) {
442- someConfig , ctx := ore.Get [string ](ctx, " someConfig" )
456+ ore.RegisterFunc [*SomeService](ore.Scoped , func (ctx context.Context ) (*SomeService, context.Context ) {
457+ someConfig , ctx := ore.GetKeyed [string ](ctx, " someConfig" )
443458 return &SomeService{someConfig}, ctx
444459})
445460
446461// someConfig is unknow at registration time because
447462// this value depends on the future user's request
448- ore.RegisterPlaceHolder [string ](" someConfig" )
463+ ore.RegisterKeyedPlaceholder [string ](" someConfig" )
449464
450465// a new request arrive
451466ctx := context.Background ()
@@ -455,14 +470,14 @@ ctx = context.WithValue(ctx, "role", "admin")
455470// inject a different somConfig value depending on the request's content
456471userRole := ctx.Value (" role" ).(string )
457472if userRole == " admin" {
458- ctx = ore.ProvideScopedValue (ctx, " Admin config" , " someConfig" )
473+ ctx = ore.ProvideKeyedScopedValue (ctx, " Admin config" , " someConfig" )
459474} else if userRole == " supervisor" {
460- ctx = ore.ProvideScopedValue (ctx, " Supervisor config" , " someConfig" )
475+ ctx = ore.ProvideKeyedScopedValue (ctx, " Supervisor config" , " someConfig" )
461476} else if userRole == " user" {
462477 if (isAuthenticatedUser) {
463- ctx = ore.ProvideScopedValue (ctx, " Public user config" , " someConfig" )
478+ ctx = ore.ProvideKeyedScopedValue (ctx, " Private user config" , " someConfig" )
464479 } else {
465- ctx = ore.ProvideScopedValue (ctx, " Private user config" , " someConfig" )
480+ ctx = ore.ProvideKeyedScopedValue (ctx, " Public user config" , " someConfig" )
466481 }
467482}
468483
@@ -473,14 +488,14 @@ fmt.Println(service.someConfig) //"Admin config"
473488
474489([ See full codes here] ( ./examples/placeholderdemo/main.go ) )
475490
476- - ` ore.RegisterPlaceHolder [T](key...) ` registers a future value with Scoped lifetime.
491+ - ` ore.RegisterPlaceholder [T](key...) ` registers a future value with Scoped lifetime.
477492 - This value will be injected in runtime using the ` ProvideScopedValue ` function.
478493 - Resolving objects which depend on this value will panic if the value has not been provided.
479494
480495- ` ore.ProvideScopedValue[T](context, value T, key...) ` injects a concrete value into the given context
481496 - ` ore ` can access (` Get() ` or ` GetList() ` ) to this value only if the corresponding placeholder (which matches the type and keys) is registered.
482497
483- - A value provided to a placeholder would never replace value returned by other resolvers. It's the opposite, if a type (and key) could be resolved by a real resolver (such as ` RegisterLazyFunc ` , ` RegisterLazyCreator ` ...), then the later would take precedent.
498+ - A value provided to a placeholder would never replace value returned by other resolvers. It's the opposite, if a type (and key) could be resolved by a real resolver (such as ` RegisterFunc ` , ` RegisterCreator ` ...), then the later would take precedent.
484499
485500<br />
486501
@@ -513,7 +528,7 @@ func (gc *genericCounter[T]) GetCount(ctx context.Context) T {
513528``` go
514529
515530// register
516- ore.RegisterLazyFunc [GenericCounter[int ]](ore.Scoped , func (ctx context.Context ) (GenericCounter[int ], context.Context ) {
531+ ore.RegisterFunc [GenericCounter[int ]](ore.Scoped , func (ctx context.Context ) (GenericCounter[int ], context.Context ) {
517532 return &genericCounter[int ]{}, ctx
518533})
519534
@@ -530,15 +545,15 @@ goos: windows
530545goarch: amd64
531546pkg: github.com/firasdarwish/ore
532547cpu: 13th Gen Intel(R) Core(TM) i9-13900H
533- BenchmarkRegisterLazyFunc -20 5706694 196.9 ns/op
534- BenchmarkRegisterLazyCreator -20 6283534 184.5 ns/op
535- BenchmarkRegisterEagerSingleton -20 5146953 211.5 ns/op
536- BenchmarkInitialGet-20 3440072 352.1 ns/op
537- BenchmarkGet-20 9806043 121.8 ns/op
538- BenchmarkInitialGetList-20 1601787 747.9 ns/op
539- BenchmarkGetList-20 4237449 282.1 ns/op
548+ BenchmarkRegisterFunc -20 5612482 214.6 ns/op
549+ BenchmarkRegisterCreator -20 6498038 174.1 ns/op
550+ BenchmarkRegisterSingleton -20 5474991 259.1 ns/op
551+ BenchmarkInitialGet-20 2297595 514.3 ns/op
552+ BenchmarkGet-20 9389530 122.1 ns/op
553+ BenchmarkInitialGetList-20 1000000 1072 ns/op
554+ BenchmarkGetList-20 3970850 301.7 ns/op
540555PASS
541- ok github.com/firasdarwish/ore 11.427s
556+ ok github.com/firasdarwish/ore 10.883s
542557```
543558
544559Checkout also [ examples/benchperf/README.md] ( examples/benchperf/README.md )
0 commit comments