Package ioc provides inversion of control containers, reflection helpers (GetNamedSetter, GetNamedInstance, GetNamedType) and Factory helpers (Resolve/ResolveNamed).
The ioc.Container and ioc.Values structs implement the Factory interface.
Package ioc is designed with the following goals in mind:
- Well defined behavior (noted in comments and ensured by tests)
- Idiomatic Go usage (within reason)
- Cater for different use cases (e.g. ResolveNamed within Factory functions, MustResolvedNamed for web request scopes)
- Robust runtime behavior (crash safe)
- avoid infinite recursion on resolve
- raise errors on configuration and behavioral errors
- custom ioc.Error struct for diagnosing configuration and behavioral issues, containing the following metadata: calling function, file and line number, called function on package ioc, requested type and name, and an error code representing the type of error.
- Predictable and reasonably efficient performance and memory usage (*to be ensured by benchmark tests)
Package ioc is not dependent on the net/http package.
Please note that package ioc is of production quality, but hasn't been thoroughly tested in production.
go get -u github.com/shelakel/go-ioc
See GoDoc on Github
This project is under the MIT License. See the LICENSE file for the full license text.
Please see GoDoc on Github and *_test.go files.
Due to the use of the reflect package, ioc.Container and ioc.Values are not well suited for temporary storage (e.g. passing state to functions on a hot path).
More benchmarks to be added during optimization.
go test -run=XXX -bench=. -benchmem=true
See reflect_cpu_prof_latest.svg for a CPU profile of the runtime reflection functions.
Benchmark | Iterations | Avg | Alloc | # Alloc |
---|---|---|---|---|
BenchmarkGetNamedSetter_Int | 20000000 | 92.0 ns/op | 33 B/op | 1 allocs/op |
BenchmarkGetNamedSetter_String | 20000000 | 92.9 ns/op | 33 B/op | 1 allocs/op |
BenchmarkGetNamedSetter_Interface | 20000000 | 96.5 ns/op | 33 B/op | 1 allocs/op |
BenchmarkGetNamedSetter_AnonStruct | 20000000 | 114 ns/op | 33 B/op | 1 allocs/op |
BenchmarkGetNamedSetter_Struct | 20000000 | 93.3 ns/op | 33 B/op | 1 allocs/op |
BenchmarkGetNamedSetter_DblPtr | 20000000 | 109 ns/op | 33 B/op | 1 allocs/op |
BenchmarkGetNamedInstance_Int | 20000000 | 102 ns/op | 33 B/op | 1 allocs/op |
BenchmarkGetNamedInstance_String | 20000000 | 102 ns/op | 33 B/op | 1 allocs/op |
BenchmarkGetNamedInstance_Interface | 20000000 | 108 ns/op | 33 B/op | 1 allocs/op |
BenchmarkGetNamedInstance_AnonStruct | 20000000 | 120 ns/op | 33 B/op | 1 allocs/op |
BenchmarkGetNamedInstance_Struct | 20000000 | 101 ns/op | 33 B/op | 1 allocs/op |
BenchmarkGetNamedInstance_DblPtr | 20000000 | 120 ns/op | 33 B/op | 1 allocs/op |
BenchmarkGetNamedType_Int | 100000000 | 20.8 ns/op | 0 B/op | 0 allocs/op |
BenchmarkGetNamedType_String | 100000000 | 20.9 ns/op | 0 B/op | 0 allocs/op |
BenchmarkGetNamedType_Interface | 100000000 | 20.8 ns/op | 0 B/op | 0 allocs/op |
BenchmarkGetNamedType_AnonStruct | 50000000 | 33.4 ns/op | 0 B/op | 0 allocs/op |
BenchmarkGetNamedType_Struct | 100000000 | 20.9 ns/op | 0 B/op | 0 allocs/op |
BenchmarkGetNamedType_DblPtr | 50000000 | 33.4 ns/op | 0 B/op | 0 allocs/op |
Preliminary benchmarking on my machine (i7-4770K, 2400MHz RAM) yielded 200 ns per Set/Get operation on ioc.Values, 400 ns per cached/singleton Resolve and 1300 ns per request to resolve via the factory function.
Tests are written using Ginkgo with the Gomega matchers.
Benchmark functions are written using the testing package.
- This package isn't actively being worked on *
- Improve performance - for now it is what it is due to the inherent limitations/cost of reflection in Go. This package is well suited for constructing singletons, not so much for use in a 'per request' type scenario.
- Populate function that uses a Factory to populate struct instances via dependency injection on tagged fields. The current thinking is to support dynamic population e.g. standard ioc="constant", dynamic ioc_route="id" via ResolveNamed((*Factory),"route") -> (dynamic Factory).ResolveNamed((type), "id").
- Improve README with Usage examples and topics.
Contributions are welcome, especially in the area of additional tests and performance enhancements.
- Find an issue that bugs you / open a new one.
- Discuss.
- Branch off the develop branch, commit, test.
- Submit a pull request / attach the commits to the issue.