forked from midwayjs/midway
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathioc.html
334 lines (280 loc) · 76.2 KB
/
ioc.html
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>依赖注入手册 | Midway</title>
<meta name="description" content="面向未来的 Web 全栈应用开发框架">
<link rel="preload" href="/midway/assets/css/0.styles.fa8c08d7.css" as="style"><link rel="preload" href="/midway/assets/js/app.14fe5da9.js" as="script"><link rel="preload" href="/midway/assets/js/10.abdcde9d.js" as="script"><link rel="prefetch" href="/midway/assets/js/11.07a451b7.js"><link rel="prefetch" href="/midway/assets/js/12.294f0379.js"><link rel="prefetch" href="/midway/assets/js/13.bd0415dc.js"><link rel="prefetch" href="/midway/assets/js/2.e3c16dc1.js"><link rel="prefetch" href="/midway/assets/js/3.b00561a6.js"><link rel="prefetch" href="/midway/assets/js/4.686a1230.js"><link rel="prefetch" href="/midway/assets/js/5.a2910199.js"><link rel="prefetch" href="/midway/assets/js/6.421d4a32.js"><link rel="prefetch" href="/midway/assets/js/7.8904f0df.js"><link rel="prefetch" href="/midway/assets/js/8.2d8fb4cb.js"><link rel="prefetch" href="/midway/assets/js/9.807c7f01.js">
<link rel="stylesheet" href="/midway/assets/css/0.styles.fa8c08d7.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/midway/" class="home-link router-link-active"><!----> <span class="site-name">Midway</span></a> <div class="links" style="max-width:nullpx;"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/midway/" class="nav-link">首页</a></div><div class="nav-item"><a href="/midway/guide.html" class="nav-link">使用文档</a></div><div class="nav-item"><a href="/midway/ioc.html" aria-current="page" class="nav-link router-link-exact-active router-link-active">依赖注入手册</a></div><div class="nav-item"><a href="/midway/tool_set.html" class="nav-link">工具集</a></div><div class="nav-item"><a href="/midway/ts_start.html" class="nav-link">TS 新手指南</a></div><div class="nav-item"><a href="http://midwayjs.org/midway/api-reference/globals.html" target="_blank" rel="noopener noreferrer" class="nav-link external">
API
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title">MidwayJs 系列产品</span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>框架</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/midway/" class="nav-link">Midway - 面向未来的 Web 全栈框架</a></li></ul></li><li class="dropdown-item"><h4>应用管理</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="http://midwayjs.org/pandora/" target="_blank" rel="noopener noreferrer" class="nav-link external">
Pandora.js - Node.js 应用管理器
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></li></ul></li><li class="dropdown-item"><h4>监控产品</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="https://github.com/midwayjs/sandbox-docker" target="_blank" rel="noopener noreferrer" class="nav-link external">
Sandbox - 私有化 Node.js 监控产品
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></li></ul></li><li class="dropdown-item"><h4>Node.js 依赖注入模块</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="http://midwayjs.org/injection" target="_blank" rel="noopener noreferrer" class="nav-link external">
Injection - 让你的应用用上 IoC,体验依赖注入的感觉
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title">Languages</span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/midway/ioc.html" aria-current="page" class="nav-link router-link-exact-active router-link-active">zh-CN</a></li><li class="dropdown-item"><!----> <a href="/midway/en/ioc.html" class="nav-link">en-US</a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <div class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/midway/" class="nav-link">首页</a></div><div class="nav-item"><a href="/midway/guide.html" class="nav-link">使用文档</a></div><div class="nav-item"><a href="/midway/ioc.html" aria-current="page" class="nav-link router-link-exact-active router-link-active">依赖注入手册</a></div><div class="nav-item"><a href="/midway/tool_set.html" class="nav-link">工具集</a></div><div class="nav-item"><a href="/midway/ts_start.html" class="nav-link">TS 新手指南</a></div><div class="nav-item"><a href="http://midwayjs.org/midway/api-reference/globals.html" target="_blank" rel="noopener noreferrer" class="nav-link external">
API
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title">MidwayJs 系列产品</span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>框架</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/midway/" class="nav-link">Midway - 面向未来的 Web 全栈框架</a></li></ul></li><li class="dropdown-item"><h4>应用管理</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="http://midwayjs.org/pandora/" target="_blank" rel="noopener noreferrer" class="nav-link external">
Pandora.js - Node.js 应用管理器
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></li></ul></li><li class="dropdown-item"><h4>监控产品</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="https://github.com/midwayjs/sandbox-docker" target="_blank" rel="noopener noreferrer" class="nav-link external">
Sandbox - 私有化 Node.js 监控产品
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></li></ul></li><li class="dropdown-item"><h4>Node.js 依赖注入模块</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="http://midwayjs.org/injection" target="_blank" rel="noopener noreferrer" class="nav-link external">
Injection - 让你的应用用上 IoC,体验依赖注入的感觉
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title">Languages</span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/midway/ioc.html" aria-current="page" class="nav-link router-link-exact-active router-link-active">zh-CN</a></li><li class="dropdown-item"><!----> <a href="/midway/en/ioc.html" class="nav-link">en-US</a></li></ul></div></div> <!----></nav> <ul class="sidebar-links"><li><div class="sidebar-group first"><p class="sidebar-heading open"><span>依赖注入手册</span> <!----></p> <ul class="sidebar-group-items"><li><a href="/midway/ioc.html#背景" class="sidebar-link">背景</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#ioc-概览" class="sidebar-link">IoC 概览</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#使用-injection-解耦" class="sidebar-link">使用 injection 解耦</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#获取-ioc-容器" class="sidebar-link">获取 IoC 容器</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#对象定义" class="sidebar-link">对象定义</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#绑定对象定义" class="sidebar-link">绑定对象定义</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#普通情况下获取对象" class="sidebar-link">普通情况下获取对象</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#使用装饰器注入" class="sidebar-link">使用装饰器注入</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/midway/ioc.html#provide" class="sidebar-link">@provide()</a></li><li class="sidebar-sub-header"><a href="/midway/ioc.html#inject" class="sidebar-link">@inject()</a></li></ul></li><li><a href="/midway/ioc.html#对象-id" class="sidebar-link">对象 id</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#构造器注入" class="sidebar-link">构造器注入</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#配置作用域" class="sidebar-link">配置作用域</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#异步初始化" class="sidebar-link">异步初始化</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#动态函数注入" class="sidebar-link">动态函数注入</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#注入已有对象" class="sidebar-link">注入已有对象</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/midway/ioc.html#通过依赖图排错" class="sidebar-link">通过依赖图排错</a><ul class="sidebar-sub-headers"></ul></li></ul></div></li></ul> </div> <div class="page"> <div class="content"><h1 id="依赖注入手册"><a href="#依赖注入手册" class="header-anchor">#</a> 依赖注入手册</h1> <div class="warning custom-block"><p class="custom-block-title">WARNING</p> <p>本文档已迁移至 <a href="https://midwayjs.org/injection/guide.html" target="_blank" rel="noopener noreferrer">新地址<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a>,此处内容不再继续更新。</p></div> <p>Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。</p> <h2 id="背景"><a href="#背景" class="header-anchor">#</a> 背景</h2> <p>midway 默认使用 <a href="http://web.npm.alibaba-inc.com/package/injection" target="_blank" rel="noopener noreferrer">injection<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> 这个包来做依赖注入,这个包也是 MidwayJs 团队根据业界已有的实现而产出的自研产品,它除了常见的依赖了注入之外,还满足了 Midway 自身的一些特殊需求。</p> <p>这篇文章不仅仅是 IoC 体系的介绍,也是属于 <a href="http://web.npm.alibaba-inc.com/package/injection" target="_blank" rel="noopener noreferrer">injection<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> 这个包的一份使用文档。</p> <p>你不仅可以在 Midway 的开发过程中用到它,如果你希望,它也可以在你的模块开发中帮助到你,它可以单独使用,也可以和现有框架集成,比如 <code>koa</code>, <code>thinkjs</code> 等。</p> <div class="tip custom-block"><p class="custom-block-title">TIP</p> <p>我们在 midway 包上做了自动导出,所以 injection 包中的模块,都能从 midway 中获取到。
import {Container} from 'injection' 和 import {Container} from 'midway' 是一样的。</p></div> <h2 id="ioc-概览"><a href="#ioc-概览" class="header-anchor">#</a> IoC 概览</h2> <p>IoC(<a href="https://en.wikipedia.org/wiki/Inversion_of_control" target="_blank" rel="noopener noreferrer">Inversion of control<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a>) 控制反转,是 Java Spring 中非常重要的思想和核心,有不少人是第一次听说,也不禁会有许多疑问。</p> <ul><li>什么是控制反转?</li> <li>什么是依赖注入?</li> <li>它们之间有什么关系?</li></ul> <p>软件中的对象就像齿轮一样,协同工作,但是互相耦合,一个零件不能正常工作,整个系统就崩溃了。这是一个强耦合的系统。</p> <p>现在,伴随着工业级应用的规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖性关系,因此,架构师和设计师对于系统的分析和设计,将面临更大的挑战。</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token comment">// 常见的依赖</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span><span class="token constant">A</span><span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./A'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span><span class="token constant">B</span><span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./B'</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">C</span> <span class="token punctuation">{</span>
<span class="token function">consturctor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>a <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">A</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>b <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">B</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>这里的 A 被 B 和 C 所依赖,而且在构造器需要进行实例化操作,这样的依赖关系在测试中会非常麻烦。这个依赖,一般被叫做 "耦合",而耦合度过高的系统,必然会出现牵一发而动全身的情形。</p> <p>为了解决对象间耦合度过高的问题,软件专家 Michael Mattson 提出了 IoC 理论,用来实现对象之间的“解耦”。</p> <p>控制反转(Inversion of Control)是一种是面向对象编程中的一种设计原则,用来减低计算机代码之间的耦合度。</p> <h2 id="使用-injection-解耦"><a href="#使用-injection-解耦" class="header-anchor">#</a> 使用 injection 解耦</h2> <p>如果你使用了 midway,这些创建的过程将会自动完成,这里为了更好理解,我们将从头开始展示。</p> <p>首先是安装依赖:</p> <div class="language-bash extra-class"><pre class="language-bash"><code><span class="token function">npm</span> i injection --save
</code></pre></div><p>然后我们将上面的代码进行解耦。</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token comment">// 使用 IoC</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>Container<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'injection'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span><span class="token constant">A</span><span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./A'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span><span class="token constant">B</span><span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./B'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> container <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Container</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">container</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token constant">A</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">container</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token constant">B</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">C</span> <span class="token punctuation">{</span>
<span class="token function">consturctor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>a <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">'A'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>b <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">'B'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>这里的 <code>container</code> 就是 IoC 容器,是依赖注入这种设计模式的一种实现,使得 C 和 A, B 没有了强耦合关系,甚至,我们可以把 C 也交给 IoC 容器,所以,IoC 容器成了整个系统的关键核心。</p> <div class="tip custom-block"><p class="custom-block-title">注意</p> <p>IoC 容器就像是一个对象池,管理这每个对象实例的信息(Class Definition),所以用户无需关心什么时候创建,当用户希望拿到对象的实例 (Object Instance) 时,可以直接拿到实例,容器会 <strong>自动将所有依赖的对象都自动实例化</strong>。</p></div> <h2 id="获取-ioc-容器"><a href="#获取-ioc-容器" class="header-anchor">#</a> 获取 IoC 容器</h2> <p>所谓的容器就是一个对象池,它会在应用初始化的时候自动处理类的依赖,并将类进行实例化。比如下面的 <code>UserService</code> 类,在经过容器初始化之后,会自动实例化,并且对 <code>userModel</code> 进行赋值,看不到实例化的过程。</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">class</span> <span class="token class-name">UserService</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> userModel<span class="token punctuation">;</span>
<span class="token keyword">async</span> <span class="token function">getUser</span><span class="token punctuation">(</span><span class="token parameter">uid</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// TODO</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>Midway 内部使用了自动扫描的机制,在应用初始化之前,会扫描所有的文件,包含装饰器的文件会 <strong>自动绑定</strong> 到容器。</p> <p>injection 的容器有几种:</p> <ul><li>AppliationContext 基础容器,提供了基础的增加定义和根据定义获取对象实例的能力</li> <li>Container 用的最多的容器,做了上层封装,通过 bind 函数能够方便的生成类定义,midway 从此类开始扩展</li> <li>RequestContext 用于请求链路上的容器,会自动销毁对象并依赖另一个容器创建实例。</li></ul> <p>其中 <code>Container</code> 是我们最常用的容器,下面的代码就是创建一个容器。</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">import</span> <span class="token punctuation">{</span>Container<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'injection'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> container <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Container</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="对象定义"><a href="#对象定义" class="header-anchor">#</a> 对象定义</h2> <p>一个对象的基本元信息,比如名字,是否异步,有哪些属性,依赖等等,我们把这些信息组合到一起,形成一个对象定义。</p> <p>对象定义往往表现在他的基础类型上, injection 内置了名为 <code>ObjectDefinition</code> 的对象定义类,它包含一系列属性,比如:</p> <ul><li>有哪些属性</li> <li>是否有依赖的对象</li> <li>创建时是否是异步的</li> <li>初始化方法是哪个</li> <li>是否自动装配</li></ul> <p>以上只是列举了一小部分,通过这个定义,容器就可以将一个对象简单的创建出来。</p> <p><code>ObjectDefinition</code> 的具体属性文档,可以在 <a href="https://midwayjs.org/injection/api-reference/classes/objectdefinition.html" target="_blank" rel="noopener noreferrer">这里看到<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></p> <h2 id="绑定对象定义"><a href="#绑定对象定义" class="header-anchor">#</a> 绑定对象定义</h2> <p>我们在创建容器之后,将会往这个容器中添加一些对象定义,这样容器才能将对应对象创建出来。</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">class</span> <span class="token class-name">UserService</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> userModel<span class="token punctuation">;</span>
<span class="token keyword">async</span> <span class="token function">getUser</span><span class="token punctuation">(</span><span class="token parameter">uid</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// TODO</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// 内部代码</span>
<span class="token keyword">const</span> container <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Container</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 创建容器</span>
<span class="token function">container</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token string">'userService'</span><span class="token punctuation">,</span> UserService<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 可以在绑定的时候传一个名字作为 key</span>
<span class="token function">container</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span>UserService<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 也可以直接传入 Class,自动分析对象的元信息生成对象定义</span>
</code></pre></div><p><code>bind</code> 方法通过传入类型,自动分析类型上面包含的元信息,具体的 API 参数可以查看<a href="https://midwayjs.org/injection/api-reference/classes/container.html#bind" target="_blank" rel="noopener noreferrer">这里<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a>。</p> <h2 id="普通情况下获取对象"><a href="#普通情况下获取对象" class="header-anchor">#</a> 普通情况下获取对象</h2> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token comment">//... 省略绑定逻辑</span>
<span class="token keyword">const</span> userService <span class="token operator">=</span> <span class="token keyword">await</span> container<span class="token punctuation">.</span><span class="token function">getAsync</span><span class="token punctuation">(</span><span class="token string">'userService'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 这里根据 key 获取对象</span>
<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token keyword">await</span> userService<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token string">'123'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 如果对象以及对象的依赖中没有异步的情况,也可以同步获取</span>
<span class="token keyword">const</span> userService <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">'userService'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> user <span class="token operator">=</span> userService<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token string">'123'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//...</span>
</code></pre></div><p>只有绑定过的对象定义才能通过 <code>get</code> 和 <code>getAsync</code> 方法创建出来。</p> <p>如果一个对象依赖了另一个对象,那么在创建的时候,依赖的对象都会被自动创建并且在容器中管理起来。</p> <div class="tip custom-block"><p class="custom-block-title">Tip</p> <p>由于 Node.js 中大多对象或者依赖都需要支持异步的情况,所以一般情况下我们都使用 <code>getAsync</code> 方法。</p></div> <h2 id="使用装饰器注入"><a href="#使用装饰器注入" class="header-anchor">#</a> 使用装饰器注入</h2> <p>如果每次代码都需要手动绑定,然后通过 <code>get/getAsync</code> 方法拿到对应的对象,那将会非常繁琐,由于 在设计之初 midway/injection 体系就基于 ts,参考了业界的 IoC 实现,完成了属于自己的依赖注入能力,主要是通过 <code>@provide</code> 和 <code>@inject</code> 两个装饰器来完成绑定定义和自动注入属性,大大简化了代码量。</p> <div class="tip custom-block"><p class="custom-block-title">TIP</p> <p>由于使用了依赖注入体系,我们希望所有的业务代码都通过 class 语法来完成</p></div> <div class="language-typescript extra-class"><pre class="language-typescript"><code>@<span class="token function">provide</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">UserService</span> <span class="token punctuation">{</span>
@<span class="token function">inject</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
userModel<span class="token punctuation">;</span>
<span class="token keyword">async</span> <span class="token function">getUser</span><span class="token punctuation">(</span><span class="token parameter">userId</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>我们可以看到业务代码的样子和以往有着一些不同。</p> <ul><li>类加了装饰器,同时直接导出,不需要关心如何实例化</li> <li>属性加了装饰器,但是没有任何初始化以及赋值的操作即可使用</li></ul> <h3 id="provide"><a href="#provide" class="header-anchor">#</a> @provide()</h3> <p>有了 <code>@provide()</code> 装饰器,就可以简化绑定,被 IoC 容器自动扫描,并绑定定义到容器上,对应的逻辑是 <a href="#%E7%BB%91%E5%AE%9A%E5%AF%B9%E8%B1%A1%E5%AE%9A%E4%B9%89">绑定对象定义</a>。</p> <p><code>@provide(id?)</code> 的参数为对象 id,可选。</p> <div class="tip custom-block"><p class="custom-block-title">注意</p> <p>@provide 装饰器是用于自动被 IoC 容器装载。</p></div> <h3 id="inject"><a href="#inject" class="header-anchor">#</a> @inject()</h3> <p><code>@inject()</code> 的作用是将容器中的定义实例化成一个对象,并且绑定到属性中,这样,在调用的时候就可以访问到该属性。</p> <div class="warning custom-block"><p class="custom-block-title">注意</p> <p>注入的时机为构造器(new)之后,所以在构造方法(constructor)中是无法获取注入的属性的,如果要获取注入的内容,可以使用 <a href="#%E6%9E%84%E9%80%A0%E5%99%A8%E6%B3%A8%E5%85%A5">构造器注入</a>。</p></div> <p>父类的属性使用 <code>@inject()</code> 装饰器装饰,子类实例会得到装饰后的属性。</p> <div class="language-typescript extra-class"><pre class="language-typescript"><code><span class="token keyword">class</span> <span class="token class-name">Parent</span> <span class="token punctuation">{</span>
@<span class="token function">inject</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
katana1<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">Child</span> <span class="token keyword">extends</span> <span class="token class-name">Parent</span> <span class="token punctuation">{</span>
@<span class="token function">inject</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
katana2<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">Grandson</span> <span class="token keyword">extends</span> <span class="token class-name">Child</span> <span class="token punctuation">{</span>
@<span class="token function">inject</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
katana3<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p><code>Grandson</code> 的实例 <code>grandson</code> 拥有 <code>@inject()</code> 装饰器注入的
<code>grandson.katana3</code>, <code>grandson.katana2</code>, <code>grandson.katana1</code> 属性。</p> <p>实现时,会查找 <code>Gradson</code> 的原型链,遍历原型链上所有用 <code>@inject()</code> 装饰的属性,运行装饰器,注入相应的属性。</p> <p>查找类的原型使用 <a href="https://github.com/rbuckton/reflect-metadata" target="_blank" rel="noopener noreferrer">reflect-metadata<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> 仓库的 <a href="https://github.com/rbuckton/reflect-metadata/blob/c2dbe1d02ceb9987f9002eedf0cdb21d74de0019/Reflect.ts#L1553-L1583" target="_blank" rel="noopener noreferrer">OrdinaryGetPrototypeOf<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> 方法,使用 <code>recursiveGetPrototypeOf</code> 方法以数组形式返回该类的所有原型。</p> <div class="language-typescript extra-class"><pre class="language-typescript"><code><span class="token keyword">function</span> <span class="token function">recursiveGetPrototypeOf</span><span class="token punctuation">(</span><span class="token parameter">target<span class="token operator">:</span> <span class="token builtin">any</span></span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> properties <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> parent <span class="token operator">=</span> <span class="token function">ordinaryGetPrototypeOf</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>parent <span class="token operator">!==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
properties<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>parent<span class="token punctuation">)</span><span class="token punctuation">;</span>
parent <span class="token operator">=</span> <span class="token function">ordinaryGetPrototypeOf</span><span class="token punctuation">(</span>parent<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> properties<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="对象-id"><a href="#对象-id" class="header-anchor">#</a> 对象 id</h2> <p>在默认情况下,injection 会将类名变为 <code>驼峰</code> 形式作为对象 id,这样你可以通过容器获取实例。</p> <div class="language-typescript extra-class"><pre class="language-typescript"><code>container<span class="token punctuation">.</span><span class="token function">getAsync</span><span class="token punctuation">(</span><span class="token string">'userService'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 根据字符串 id 获取实例</span>
container<span class="token punctuation">.</span><span class="token function">getAsync</span><span class="token punctuation">(</span>UserService<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 传入类名,自动根据类目获取实例</span>
</code></pre></div><p>而默认情况下,Midway 的依赖注入使用的是 <code>byName</code> ,只要同名,就会自动进行注入。</p> <p>而在某些场景下,用户希望注入不同的实例,这个时候可以对默认生成的 id 进行修改。</p> <div class="language-typescript extra-class"><pre class="language-typescript"><code>@<span class="token function">provide</span><span class="token punctuation">(</span><span class="token string">'uModel'</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">UserModel</span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>
@<span class="token function">provide</span><span class="token punctuation">(</span><span class="token string">'user'</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">UserService</span> <span class="token punctuation">{</span>
@<span class="token function">inject</span><span class="token punctuation">(</span><span class="token string">'uModel'</span><span class="token punctuation">)</span>
userModel<span class="token punctuation">;</span>
<span class="token keyword">async</span> <span class="token function">getUser</span><span class="token punctuation">(</span><span class="token parameter">userId</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// 使用修改之后的 id 获取对象</span>
<span class="token keyword">const</span> userService <span class="token operator">=</span> <span class="token keyword">await</span> container<span class="token punctuation">.</span><span class="token function">getAsync</span><span class="token punctuation">(</span><span class="token string">'user'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>同理,在使用 <code>@inject</code> 的时候也可以使用不同的 id。</p> <h2 id="构造器注入"><a href="#构造器注入" class="header-anchor">#</a> 构造器注入</h2> <p>除了标准的属性注入方法之外,midway 在一定程度上支持了构造器注入的方式,来让一些应用或者三方包平稳过度。</p> <p>同样还是使用 <code>@inject</code> 装饰器。</p> <div class="language-ts extra-class"><pre class="language-ts"><code>@<span class="token function">provide</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token punctuation">{</span>
config <span class="token operator">=</span> <span class="token punctuation">{</span>
c<span class="token operator">:</span> <span class="token number">20</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
@<span class="token function">provide</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token punctuation">{</span>
config <span class="token operator">=</span> <span class="token punctuation">{</span>
c<span class="token operator">:</span> <span class="token number">40</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
@<span class="token function">provide</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">BaseService</span> <span class="token punctuation">{</span>
config<span class="token punctuation">;</span>
plugin2<span class="token punctuation">;</span>
<span class="token keyword">constructor</span><span class="token punctuation">(</span>
@<span class="token function">inject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> a<span class="token punctuation">,</span>
@<span class="token function">config</span><span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span> config<span class="token punctuation">,</span>
@<span class="token function">inject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> b<span class="token punctuation">,</span>
@<span class="token function">plugin</span><span class="token punctuation">(</span><span class="token string">'plugin2'</span><span class="token punctuation">)</span> plugin2
<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>config <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">assign</span><span class="token punctuation">(</span>config<span class="token punctuation">,</span> <span class="token punctuation">{</span>
c<span class="token operator">:</span> a<span class="token punctuation">.</span>config<span class="token punctuation">.</span>c <span class="token operator">+</span> b<span class="token punctuation">.</span>config<span class="token punctuation">.</span>c <span class="token operator">+</span> config<span class="token punctuation">.</span>c
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>plugin2 <span class="token operator">=</span> plugin2<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>在一个类的构造器中,我们可以还可以使用其他的类似 <code>@config</code>, <code>@plugin</code>, <code>@logger</code> 等装饰器。只要是通过 IoC 管理的对象,都能够被自动依赖和注入。</p> <h2 id="配置作用域"><a href="#配置作用域" class="header-anchor">#</a> 配置作用域</h2> <p>在 injection 体系中,有三种作用域。</p> <ul><li>Singleton 单例,全局唯一(进程级别)</li> <li>Request <strong>默认</strong>,请求作用域,生命周期随着请求链路,在请求链路上唯一,请求结束立即销毁</li> <li>Prototype 原型作用域,每次调用都会重复创建一个新的对象</li></ul> <p>在这三种作用域中,midway 的默认作用域为 <strong>请求作用域</strong>,这也意味着,如果我们需要将一个对象定义为其他两种作用域,需要额外的配置。</p> <p>injection 提供了 <code>@scope</code> 装饰器来定义一个类的作用域。</p> <div class="language-typescript extra-class"><pre class="language-typescript"><code>@<span class="token function">scope</span><span class="token punctuation">(</span>ScopeEnum<span class="token punctuation">.</span>Prototype<span class="token punctuation">)</span>
@<span class="token function">provide</span><span class="token punctuation">(</span><span class="token string">'petrol'</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">PetrolEngine</span> <span class="token keyword">implements</span> <span class="token class-name">Engine</span> <span class="token punctuation">{</span>
capacity <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
@<span class="token function">scope</span><span class="token punctuation">(</span>ScopeEnum<span class="token punctuation">.</span>Singleton<span class="token punctuation">)</span>
@<span class="token function">provide</span><span class="token punctuation">(</span><span class="token string">'diesel'</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">DieselEngine</span> <span class="token keyword">implements</span> <span class="token class-name">Engine</span> <span class="token punctuation">{</span>
capacity <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// in IoC Container</span>
<span class="token function">assert</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span><span class="token function">getAsync</span><span class="token punctuation">(</span><span class="token string">'petrol'</span><span class="token punctuation">)</span> <span class="token operator">===</span> container<span class="token punctuation">.</span><span class="token function">getAsync</span><span class="token punctuation">(</span><span class="token string">'petrol'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// false</span>
<span class="token function">assert</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span><span class="token function">getAsync</span><span class="token punctuation">(</span><span class="token string">'diesel'</span><span class="token punctuation">)</span> <span class="token operator">===</span> container<span class="token punctuation">.</span><span class="token function">getAsync</span><span class="token punctuation">(</span><span class="token string">'diesel'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// true</span>
</code></pre></div><p class="warning">
插件,在 midway 中为单例,不可配置。
</p> <h2 id="异步初始化"><a href="#异步初始化" class="header-anchor">#</a> 异步初始化</h2> <p>在某些情况下,我们需要一个实例在被其他依赖调用前需要初始化,如果这个初始化只是读取某个文件,那么可以写成同步方式,而如果这个初始化是从远端拿取数据或者连接某个服务,这个情况下,普通的同步代码就非常的难写。</p> <p>midway 提供了异步初始化的能力,通过 <code>@init</code> 标签来管理初始化方法。</p> <p><code>@init</code> 方法目前只能是一个。</p> <div class="language-typescript extra-class"><pre class="language-typescript"><code>@<span class="token function">provide</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">BaseService</span> <span class="token punctuation">{</span>
@<span class="token function">config</span><span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span>
config<span class="token punctuation">;</span>
@<span class="token function">plugin</span><span class="token punctuation">(</span><span class="token string">'plugin2'</span><span class="token punctuation">)</span>
plugin2<span class="token punctuation">;</span>
@<span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">async</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">await</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token parameter">resolve</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>config<span class="token punctuation">.</span>c <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><div class="warning custom-block"><p class="custom-block-title">注意</p> <p>@async 装饰器已废弃,所有的 init 方法默认都会异步,同步初始化可以直接在构造器执行,此装饰器没有意义。</p></div> <p>只要在方法上标记 <code>@init</code> 装饰器之后,这个时候会自动在实例化之后,通过异步的来调用 <code>@init</code> 标记的方法。</p> <h2 id="动态函数注入"><a href="#动态函数注入" class="header-anchor">#</a> 动态函数注入</h2> <p>在某些场景下,我们需要函数作为某个逻辑动态执行,而 IoC 中的对象属性则都是已经创建好的,无法满足动态的逻辑需求。</p> <p>比如你需要一个工厂函数,根据不同的场景返回不同的实例,也可能有一个三方包,是个函数,在业务中想要直接调用,种种的场景下,你就需要直接注入一个函数,并且在函数中拿到上下文。</p> <p>标准的函数注入样例。</p> <div class="language-typescript extra-class"><pre class="language-typescript"><code><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">contextHandler</span><span class="token punctuation">(</span><span class="token parameter">context</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token comment">// const xxx = context.getAsync('xxxx');</span>
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">providerWrapper</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token punctuation">{</span>
id<span class="token operator">:</span> <span class="token string">'contextHandler'</span><span class="token punctuation">,</span>
provider<span class="token operator">:</span> contextHandler<span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>使用端。</p> <div class="language-typescript extra-class"><pre class="language-typescript"><code>@<span class="token function">provide</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">BaseService</span> <span class="token punctuation">{</span>
@<span class="token function">inject</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token function-variable function">contextHandler</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token builtin">boolean</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>midway 通过 <code>providerWrapper</code> 函数来包裹一个函数,并且指定提供的 key,供其他 IoC 对象使用。由于函数直接传递了一个 context 对象,可以轻松的通过此对象拿到所需的其他对象,而不需要管理依赖。</p> <p>函数注入大多数为了创建一个简单的工厂。</p> <div class="language-typescript extra-class"><pre class="language-typescript"><code><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">adapterFactory</span><span class="token punctuation">(</span><span class="token parameter">context<span class="token operator">:</span> IApplicationContext</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">adapterName<span class="token operator">:</span> <span class="token builtin">string</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>adapterName <span class="token operator">===</span> <span class="token string">'google'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">await</span> context<span class="token punctuation">.</span><span class="token function">getAsync</span><span class="token punctuation">(</span><span class="token string">'googleAdapter'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>adapterName <span class="token operator">===</span> <span class="token string">'baidu'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">await</span> context<span class="token punctuation">.</span><span class="token function">getAsync</span><span class="token punctuation">(</span><span class="token string">'baiduAdapter'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// return await context.getAsync(adapterName + 'Adapter');</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">providerWrapper</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token punctuation">{</span>
id<span class="token operator">:</span> <span class="token string">'adapterFactory'</span><span class="token punctuation">,</span>
provider<span class="token operator">:</span> adapterFactory<span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>这样在业务中,可以直接来使用了。</p> <div class="language-typescript extra-class"><pre class="language-typescript"><code>
@<span class="token function">provide</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">BaseService</span> <span class="token punctuation">{</span>
@<span class="token function">config</span><span class="token punctuation">(</span><span class="token string">'adapterName'</span><span class="token punctuation">)</span>
adapterName<span class="token punctuation">;</span>
@<span class="token function">inject</span><span class="token punctuation">(</span><span class="token string">'adapterFactory'</span><span class="token punctuation">)</span>
factory<span class="token punctuation">;</span>
adapter<span class="token operator">:</span> Adapter<span class="token punctuation">;</span>
@<span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">async</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>adapter <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">factory</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>adapterName<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><div class="tip custom-block"><p class="custom-block-title">TIP</p> <p>这个函数可以是异步的 (async)。</p></div> <p>再举个例子,比如如果应用希望自己使用 sequelize, 而 sequelize 的创建 model 的过程是个异步操作,代码就可以这么写:</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> providerWrapper<span class="token punctuation">,</span> IApplicationContext <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'midway'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> Sequelize <span class="token keyword">from</span> <span class="token string">'sequelize'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Sequelize <span class="token keyword">as</span> SequelizeInstance <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'sequelize'</span><span class="token punctuation">;</span>
<span class="token comment">// 可以直接写 async 方法</span>
<span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">factory</span><span class="token punctuation">(</span><span class="token parameter">context<span class="token operator">:</span> IApplicationContext</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> instance <span class="token operator">=</span> <span class="token keyword">await</span> context<span class="token punctuation">.</span>getAsync<span class="token operator"><</span>SequelizeInstance<span class="token operator">></span><span class="token punctuation">(</span><span class="token string">'coreDB'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> UiKeyTraceModel <span class="token operator">=</span> instance<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> <span class="token punctuation">{</span>
gmtCreate<span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token keyword">type</span><span class="token operator">:</span> Sequelize<span class="token punctuation">.</span><span class="token constant">DATE</span><span class="token punctuation">,</span>
allowNull<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
field<span class="token operator">:</span> <span class="token string">'gmt_create'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
gmtModified<span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token keyword">type</span><span class="token operator">:</span> Sequelize<span class="token punctuation">.</span><span class="token constant">DATE</span><span class="token punctuation">,</span>
allowNull<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
field<span class="token operator">:</span> <span class="token string">'gmt_modified'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
timestamps<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
createdAt<span class="token operator">:</span> <span class="token string">'gmt_create'</span><span class="token punctuation">,</span>
updatedAt<span class="token operator">:</span> <span class="token string">'gmt_modified'</span><span class="token punctuation">,</span>
freezeTableName<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
tableName<span class="token operator">:</span> <span class="token string">'xxxx'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> UiKeyTraceModel<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">providerWrapper</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token punctuation">{</span>
id<span class="token operator">:</span> <span class="token string">'keyTraceModel'</span><span class="token punctuation">,</span>
provider<span class="token operator">:</span> factory
<span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>通过 <code>providerWrapper</code> 我们将一个原本的函数写法进行了包裹,和现有的依赖注入体系可以融合到一起,让容器能够统一管理。</p> <h2 id="注入已有对象"><a href="#注入已有对象" class="header-anchor">#</a> 注入已有对象</h2> <p>有时候,应用已经有现有的实例,而不是类,比如引入了一个第三库,这个时候如果希望对象能够被其他 IoC 容器中的实例引用,也可以通过增加对象的方式进行处理。</p> <p>我们拿常见的 http 请求库 <a href="https://www.npmjs.com/package/urllib" target="_blank" rel="noopener noreferrer">urllib<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> 来举例。</p> <p>假如我们希望在不同的类中来使用,并且不通过 require 的方式,你需要在容器的入口通过 <a href="https://midwayjs.org/injection/api-reference/classes/container.html#registerobject" target="_blank" rel="noopener noreferrer">registerobject<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> 方法添加这个对象。</p> <p>在添加的时候需要给出一个 key,方便其他类中注入。</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token comment">// in global file</span>
<span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> urllib <span class="token keyword">from</span> <span class="token string">'urllib'</span><span class="token punctuation">;</span>
container<span class="token punctuation">.</span><span class="token function">registerobject</span><span class="token punctuation">(</span><span class="token string">'httpclient'</span><span class="token punctuation">,</span> urllib<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>这个时候就可以在任意的类中通过 <code>@inject</code> 来使用了。</p> <div class="language-ts extra-class"><pre class="language-ts"><code>@<span class="token function">provide</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">BaseService</span> <span class="token punctuation">{</span>
@<span class="token function">inject</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
httpclient<span class="token punctuation">;</span>
<span class="token keyword">async</span> <span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span>httpclient<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span><span class="token string">'/api/getuser'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><div class="tip custom-block"><p class="custom-block-title">TIP</p> <p>在 midway 中可以在 src/app.ts 中进行添加。</p></div> <h2 id="通过依赖图排错"><a href="#通过依赖图排错" class="header-anchor">#</a> 通过依赖图排错</h2> <p>在业务代码中,我们可能会碰到依赖注入不生效或者作用域配置错误的问题,这个时候由于容器管理的问题显得不透明,用户也不太清楚容器里有哪些东西,分别依赖了什么。</p> <p>我们提供了一个依赖树生成的方法,目前可以通过它生成文本形式的图形。</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">const</span> container <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Container</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">container</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span>UserService<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">container</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span>UserController<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">container</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span>DbAPI<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> newTree <span class="token operator">=</span> <span class="token keyword">await</span> container<span class="token punctuation">.</span><span class="token function">dumpDependency</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>newTree<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>通过 <code>dumpDependency</code> 方法生成的文本,可以直接在 <a href="http://viz-js.com/" target="_blank" rel="noopener noreferrer">viz-js<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> 渲染为图案,方便排查问题。</p> <p>也可以通过安装 <code>graphviz</code> 等工具将文本树转化为图片形式。</p> <div class="tip custom-block"><p class="custom-block-title">TIP</p> <p>midway 在启动时会将依赖树生成到 /run 目录下,方便排错。</p></div></div> <div class="page-edit"><!----> <!----></div> <!----> </div> <!----></div></div>
<script src="/midway/assets/js/app.14fe5da9.js" defer></script><script src="/midway/assets/js/10.abdcde9d.js" defer></script>
</body>
</html>