通过对web应用框架背后原理的探索,引入了依赖注入的概念。如果你需要读懂或者写一个框架的话,依赖注入的思想绝对能帮到你。本文记录对依赖注入的探索。
区分依赖和宿主
现在我们把问题简化一下:
package main
import "fmt"
func MethodA(name string, f func(a int, b string)) {
fmt.Println("Enter MethodA:", name)
f(3030, "zdd") // 给f注入参数
fmt.Println("Exit MethodA:", name)
}
func MethodB(a int, b string) {
fmt.Println(a, b)
}
func main() {
d := MethodB
MethodA("zddhub", d)
}
在上述的例子中,为了完成MethodA的功能,需要依赖MethodB方法的实现,把MethodB方法叫做MethodA的依赖(Dependency)
, MethodA叫做宿主(Host)
。上面的例子直接在Host中调用f(3030, "zdd")
来给依赖注入参数。或者换一个角度理解,将自定义的方法MethodB整体注入到MethodA的执行环境中
。为了通用性考虑,通常会实现一个依赖注入器。
依赖注入器
接下来实现一个依赖注入器(Injector)。在web应用框架的例子中,我们发现,在Host中,只能拿到依赖方法的参数类型,而我们需要将参数类型和参数值建立联系,因此,在Injector中封装一个map[Type]Value
是自然而然的选择。
package main
import (
"fmt"
"reflect"
)
type Injector struct {
mappers map[reflect.Type]reflect.Value // 根据类型map实际的值
}
func (inj *Injector) SetMap(value interface{}) {
inj.mappers[reflect.TypeOf(value)] = reflect.ValueOf(value)
}
func (inj *Injector) Get(t reflect.Type) reflect.Value {
return inj.mappers[t]
}
func (inj *Injector) Invoke(i interface{}) []reflect.Value {
t := reflect.TypeOf(i)
if t.Kind() != reflect.Func {
panic("Should invoke a function!")
}
inValues := make([]reflect.Value, t.NumIn())
for k := 0; k < t.NumIn(); k++ {
inValues[k] = inj