// Container 是一个服务容器,提供绑定服务和获取服务的功能
type Container interface {
// Bind 绑定一个服务提供者,如果关键字凭证已经存在,会进行替换操作,返回 error
Bind(provider ServiceProvider) error
// IsBind 关键字凭证是否已经绑定服务提供者
IsBind(key string) bool
// Make 根据关键字凭证获取一个服务,
Make(key string) (interface{}, error)
// MustMake 根据关键字凭证获取一个服务,如果这个关键字凭证未绑定服务提供者,那么会 panic。
// 所以在使用这个接口的时候请保证服务容器已经为这个关键字凭证绑定了服务提供者。
MustMake(key string) interface{}
// MakeNew 根据关键字凭证获取一个服务,只是这个服务并不是单例模式的
// 它是根据服务提供者注册的启动函数和传递的 params 参数实例化出来的
// 这个函数在需要为不同参数启动不同实例的时候非常有用
MakeNew(key string, params []interface{}) (interface{}, error)
}
我们就定义一个 HadeContainer 数据结构来实现 Container 接口,因为功能是提供绑定服务和获取服务,需要根据关键字获取一个对象,所以 Hash Map 是符合需求的。
// HadeContainer 是服务容器的具体实现
type HadeContainer struct {
Container // 强制要求 HadeContainer 实现 Container 接口
// providers 存储注册的服务提供者,key 为字符串凭证
providers map[string]ServiceProvider
// instance 存储具体的实例,key 为字符串凭证
instances map[string]interface{}
// lock 用于锁住对容器的变更操作
lock sync.RWMutex
}
Bind 方法
// Bind 将服务容器和关键字做了绑定
func (hade *HadeContainer) Bind(provider ServiceProvider) error {
hade.lock.Lock()
defer hade.lock.Unlock()
key := provider.Name()
hade.providers[key] = provider
// if provider is not defer
if provider.IsDefer() == false {
if err := provider.Boot(hade); err != nil {
return err
}
// 实例化方法
params := provider.Params(hade)
method := provider.Register(hade)
instance, err := method(params...)
if err != nil {
return errors.New(err.Error())
}
hade.instances[key] = instance
}
return nil
}
Make 方法
// Make 方式调用内部的 make 实现
func (hade *HadeContainer) Make(key string) (interface{}, error) {
return hade.make(key, nil, false)
}
// MakeNew 方式使用内部的 make 初始化
func (hade *HadeContainer) MakeNew(key string, params []interface{}) (interface{}, error) {
return hade.make(key, params, true)
}
// 真正的实例化一个服务
func (hade *HadeContainer) make(key string, params []interface{}, forceNew bool) (interface{}, error) {
hade.lock.RLock()
defer hade.lock.RUnlock()
// 查询是否已经注册了这个服务提供者,如果没有注册,则返回错误
sp := hade.findServiceProvider(key)
if sp == nil {
return nil, errors.New("contract " + key + " have not register")
}
if forceNew {
return hade.newInstance(sp, params)
}
// 不需要强制重新实例化,如果容器中已经实例化了,那么就直接使用容器中的实例
if ins, ok := hade.instances[key]; ok {
return ins, nil
}
// 容器中还未实例化,则进行一次实例化
inst, err := hade.newInstance(sp, nil)
if err != nil {
return nil, err
}
hade.instances[key] = inst
return inst, nil
}
那么对应到框架中,可以将服务容器存放在 Engine 中,并且在 Engine 初始化 Context 的时候,将服务容器传递进入 Context。
type Engine struct {
// 容器
container framework.Container
...
}
func New() *Engine {
debugPrintWARNINGNew()
engine := &Engine{
...
// 这里注入了 container
container: framework.NewHadeContainer(),
...
}
...
return engine
}