1. // Container 是一个服务容器,提供绑定服务和获取服务的功能
    2. type Container interface {
    3. // Bind 绑定一个服务提供者,如果关键字凭证已经存在,会进行替换操作,返回 error
    4. Bind(provider ServiceProvider) error
    5. // IsBind 关键字凭证是否已经绑定服务提供者
    6. IsBind(key string) bool
    7. // Make 根据关键字凭证获取一个服务,
    8. Make(key string) (interface{}, error)
    9. // MustMake 根据关键字凭证获取一个服务,如果这个关键字凭证未绑定服务提供者,那么会 panic。
    10. // 所以在使用这个接口的时候请保证服务容器已经为这个关键字凭证绑定了服务提供者。
    11. MustMake(key string) interface{}
    12. // MakeNew 根据关键字凭证获取一个服务,只是这个服务并不是单例模式的
    13. // 它是根据服务提供者注册的启动函数和传递的 params 参数实例化出来的
    14. // 这个函数在需要为不同参数启动不同实例的时候非常有用
    15. MakeNew(key string, params []interface{}) (interface{}, error)
    16. }

    我们就定义一个 HadeContainer 数据结构来实现 Container 接口,因为功能是提供绑定服务和获取服务,需要根据关键字获取一个对象,所以 Hash Map 是符合需求的。

    1. // HadeContainer 是服务容器的具体实现
    2. type HadeContainer struct {
    3. Container // 强制要求 HadeContainer 实现 Container 接口
    4. // providers 存储注册的服务提供者,key 为字符串凭证
    5. providers map[string]ServiceProvider
    6. // instance 存储具体的实例,key 为字符串凭证
    7. instances map[string]interface{}
    8. // lock 用于锁住对容器的变更操作
    9. lock sync.RWMutex
    10. }

    Bind 方法

    1. // Bind 将服务容器和关键字做了绑定
    2. func (hade *HadeContainer) Bind(provider ServiceProvider) error {
    3. hade.lock.Lock()
    4. defer hade.lock.Unlock()
    5. key := provider.Name()
    6. hade.providers[key] = provider
    7. // if provider is not defer
    8. if provider.IsDefer() == false {
    9. if err := provider.Boot(hade); err != nil {
    10. return err
    11. }
    12. // 实例化方法
    13. params := provider.Params(hade)
    14. method := provider.Register(hade)
    15. instance, err := method(params...)
    16. if err != nil {
    17. return errors.New(err.Error())
    18. }
    19. hade.instances[key] = instance
    20. }
    21. return nil
    22. }

    Make 方法

    1. // Make 方式调用内部的 make 实现
    2. func (hade *HadeContainer) Make(key string) (interface{}, error) {
    3. return hade.make(key, nil, false)
    4. }
    5. // MakeNew 方式使用内部的 make 初始化
    6. func (hade *HadeContainer) MakeNew(key string, params []interface{}) (interface{}, error) {
    7. return hade.make(key, params, true)
    8. }
    9. // 真正的实例化一个服务
    10. func (hade *HadeContainer) make(key string, params []interface{}, forceNew bool) (interface{}, error) {
    11. hade.lock.RLock()
    12. defer hade.lock.RUnlock()
    13. // 查询是否已经注册了这个服务提供者,如果没有注册,则返回错误
    14. sp := hade.findServiceProvider(key)
    15. if sp == nil {
    16. return nil, errors.New("contract " + key + " have not register")
    17. }
    18. if forceNew {
    19. return hade.newInstance(sp, params)
    20. }
    21. // 不需要强制重新实例化,如果容器中已经实例化了,那么就直接使用容器中的实例
    22. if ins, ok := hade.instances[key]; ok {
    23. return ins, nil
    24. }
    25. // 容器中还未实例化,则进行一次实例化
    26. inst, err := hade.newInstance(sp, nil)
    27. if err != nil {
    28. return nil, err
    29. }
    30. hade.instances[key] = inst
    31. return inst, nil
    32. }

    那么对应到框架中,可以将服务容器存放在 Engine 中,并且在 Engine 初始化 Context 的时候,将服务容器传递进入 Context。

    1. type Engine struct {
    2. // 容器
    3. container framework.Container
    4. ...
    5. }
    6. func New() *Engine {
    7. debugPrintWARNINGNew()
    8. engine := &Engine{
    9. ...
    10. // 这里注入了 container
    11. container: framework.NewHadeContainer(),
    12. ...
    13. }
    14. ...
    15. return engine
    16. }