-
Notifications
You must be signed in to change notification settings - Fork 0
/
container.go
176 lines (138 loc) · 4.26 KB
/
container.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package framework
import (
"errors"
"fmt"
"sync"
)
type Container interface {
// 绑定一个服务提供者 如果凭证已经存在则替换
Bind(provider ServiceProvider) error
// 凭证是否已经绑定
IsBind(key string) bool
// 根据关键字获取服务
Make(key string) (interface{}, error)
// MustMake 根据关键字凭证获取一个服务,如果这个关键字凭证未绑定服务提供者,那么会panic。
// 所以在使用这个接口的时候请保证服务容器已经为这个关键字凭证绑定了服务提供者。
MustMake(key string) interface{}
// MakeNew 根据关键字凭证获取一个服务,只是这个服务并不是单例模式的
// 它是根据服务提供者注册的启动函数和传递的params参数实例化出来的
// 这个函数在需要为不同参数启动不同实例的时候非常有用
MakeNew(key string, params []interface{}) (interface{}, error)
}
type AnanContainer struct {
Container
// 存储注册服务的提供者
providers map[string]ServiceProvider
// 存储具体是实例
instances map[string]interface{}
// bind 和 make 防止并发操作
lock sync.RWMutex
}
func NewAnanContainer() *AnanContainer {
return &AnanContainer{
providers: map[string]ServiceProvider{},
instances: map[string]interface{}{},
lock: sync.RWMutex{},
}
}
// PrintProviders 输出服务容器中注册的关键字
func (container *AnanContainer) PrintProviders() []string {
ret := []string{}
for _, provider := range container.providers {
name := provider.Name()
line := fmt.Sprint(name)
ret = append(ret, line)
}
return ret
}
func (container *AnanContainer) Bind(provider ServiceProvider) error {
container.lock.RLock()
defer container.lock.RUnlock()
key := provider.Name()
container.providers[key] = provider //绑定服务提供者
if !provider.IsDefer() { //不延迟实例化
if err := provider.Boot(container); err != nil { //做一些初始化操作
return err
}
params := provider.Params(container)
method := provider.Register(container) //获取 实例化的方法
ins, err := method(params...)
if err != nil {
return errors.New(err.Error())
}
container.instances[key] = ins
}
return nil
}
func (container *AnanContainer) IsBind(key string) bool {
return container.findServiceProvider(key) != nil
}
// 根据key找服务提供者
func (container *AnanContainer) findServiceProvider(key string) ServiceProvider {
container.lock.RLock()
defer container.lock.RUnlock()
if sp, ok := container.providers[key]; ok {
return sp
}
return nil
}
// 实例化服务提供者
func (container *AnanContainer) newInstance(sp ServiceProvider, params []interface{}) (interface{}, error) {
if err := sp.Boot(container); err != nil {
return nil, err
}
if params == nil {
params = sp.Params(container)
}
method := sp.Register(container)
ins, err := method(params...)
if err != nil {
return nil, errors.New(err.Error())
}
return ins, nil
}
func (container *AnanContainer) Make(key string) (interface{}, error) {
return container.make(key, nil, false)
}
func (container *AnanContainer) MustMake(key string) interface{} {
serv, err := container.make(key, nil, false)
if err != nil {
panic(err)
}
return serv
}
func (container *AnanContainer) MakeNew(key string, params []interface{}) (interface{}, error) {
return container.make(key, params, true)
}
// 真正实例化一个服务
func (container *AnanContainer) make(key string, params []interface{}, forceNew bool) (interface{}, error) {
container.lock.RLock()
defer container.lock.RUnlock()
// 从提供者中寻找
sp := container.findServiceProvider(key)
if sp == nil {
return nil, errors.New("contract:" + key + " is not found")
}
if forceNew { // 是否需要根据参数重新实例化
return container.newInstance(sp, params)
}
// 查看实例中是否已经存在 存在的话返回
if ins, ok := container.instances[key]; ok {
return ins, nil
}
inst, err := container.newInstance(sp, nil)
if err != nil {
return nil, err
}
container.instances[key] = inst
return inst, nil
}
// 返回所有服务的名字
func (container *AnanContainer) NameList() []string {
var ret = []string{}
for _, provider := range container.providers {
name := provider.Name()
ret = append(ret, name)
}
return ret
}