imean-service-engine 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +77 -52
- package/dist/index.d.ts +77 -52
- package/dist/index.js +2078 -1945
- package/dist/index.mjs +2076 -1944
- package/package.json +9 -2
- package/.vscode/settings.json +0 -8
- package/src/core/checker.ts +0 -33
- package/src/core/decorators.test.ts +0 -96
- package/src/core/decorators.ts +0 -68
- package/src/core/engine.test.ts +0 -218
- package/src/core/engine.ts +0 -635
- package/src/core/errors.ts +0 -28
- package/src/core/factory.test.ts +0 -73
- package/src/core/factory.ts +0 -92
- package/src/core/logger.ts +0 -65
- package/src/core/testing.ts +0 -73
- package/src/core/types.ts +0 -191
- package/src/index.ts +0 -49
- package/src/metadata/README.md +0 -422
- package/src/metadata/metadata.test.ts +0 -369
- package/src/metadata/metadata.ts +0 -512
- package/src/plugins/action/action-plugin.test.ts +0 -660
- package/src/plugins/action/decorator.ts +0 -14
- package/src/plugins/action/index.ts +0 -4
- package/src/plugins/action/plugin.ts +0 -349
- package/src/plugins/action/types.ts +0 -49
- package/src/plugins/action/utils.test.ts +0 -196
- package/src/plugins/action/utils.ts +0 -111
- package/src/plugins/cache/adapter.test.ts +0 -689
- package/src/plugins/cache/adapter.ts +0 -324
- package/src/plugins/cache/cache-plugin.test.ts +0 -269
- package/src/plugins/cache/decorator.ts +0 -26
- package/src/plugins/cache/index.ts +0 -20
- package/src/plugins/cache/plugin.ts +0 -299
- package/src/plugins/cache/types.ts +0 -69
- package/src/plugins/client-code/client-code-plugin.test.ts +0 -511
- package/src/plugins/client-code/format.ts +0 -9
- package/src/plugins/client-code/generator.test.ts +0 -52
- package/src/plugins/client-code/generator.ts +0 -263
- package/src/plugins/client-code/index.ts +0 -15
- package/src/plugins/client-code/plugin.ts +0 -158
- package/src/plugins/client-code/types.ts +0 -52
- package/src/plugins/client-code/utils.ts +0 -164
- package/src/plugins/graceful-shutdown/graceful-shutdown-plugin.test.ts +0 -401
- package/src/plugins/graceful-shutdown/index.ts +0 -3
- package/src/plugins/graceful-shutdown/plugin.ts +0 -279
- package/src/plugins/graceful-shutdown/types.ts +0 -17
- package/src/plugins/rate-limit/rate-limit-plugin.example.ts +0 -171
- package/src/plugins/route/components/Layout.tsx +0 -42
- package/src/plugins/route/components/ServiceStatusPage.tsx +0 -141
- package/src/plugins/route/decorator.ts +0 -50
- package/src/plugins/route/index.ts +0 -16
- package/src/plugins/route/plugin.ts +0 -218
- package/src/plugins/route/route-plugin.test.ts +0 -759
- package/src/plugins/route/types.ts +0 -72
- package/src/plugins/schedule/README.md +0 -309
- package/src/plugins/schedule/decorator.ts +0 -25
- package/src/plugins/schedule/index.ts +0 -12
- package/src/plugins/schedule/mock-etcd.ts +0 -145
- package/src/plugins/schedule/plugin.ts +0 -164
- package/src/plugins/schedule/schedule-plugin.test.ts +0 -312
- package/src/plugins/schedule/scheduler.ts +0 -164
- package/src/plugins/schedule/types.ts +0 -94
- package/src/plugins/schedule/utils.test.ts +0 -163
- package/src/plugins/schedule/utils.ts +0 -41
- package/tests/integration/client.test.ts +0 -203
- package/tests/integration/dev-service.ts +0 -301
- package/tests/integration/generated/client.ts +0 -123
- package/tests/integration/start-service.ts +0 -21
- package/tsconfig.json +0 -27
- package/tsup.config.ts +0 -16
- package/vitest.config.ts +0 -19
package/src/metadata/README.md
DELETED
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
# 通用元数据工具库
|
|
2
|
-
|
|
3
|
-
## 概述
|
|
4
|
-
|
|
5
|
-
`metadata.ts` 是一个轻量级的装饰器元数据管理工具库,类似于 `reflect-metadata`,但更简单、更轻量。
|
|
6
|
-
|
|
7
|
-
## 特性
|
|
8
|
-
|
|
9
|
-
- ✅ 基于 Stage 3 装饰器标准(TypeScript 5.0+)
|
|
10
|
-
- ✅ 无需外部依赖
|
|
11
|
-
- ✅ 支持类装饰器和方法装饰器
|
|
12
|
-
- ✅ 支持方法装饰器多应用(同一方法可被多个装饰器标注)
|
|
13
|
-
- ✅ **支持双向访问**:通过 key 查找类,通过类查找 key
|
|
14
|
-
- ✅ 类型安全
|
|
15
|
-
- ✅ 简单够用
|
|
16
|
-
|
|
17
|
-
## 设计原理
|
|
18
|
-
|
|
19
|
-
### 核心数据结构
|
|
20
|
-
|
|
21
|
-
新设计采用**双向映射**机制,实现了装饰器 key 和类之间的双向访问:
|
|
22
|
-
|
|
23
|
-
#### 1. key -> classes 映射
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
const keyToClassesMap = new Map<symbol, Set<Class>>();
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
- **用途**:记录某个装饰器 key 装饰了哪些类
|
|
30
|
-
- **存储位置**:全局 Map(非 WeakMap),因为需要能够遍历所有被装饰的类
|
|
31
|
-
- **访问方式**:通过 `getClassesByKey(key)` 获取所有被该 key 装饰的类
|
|
32
|
-
|
|
33
|
-
#### 2. class -> keys 映射
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
36
|
-
// 通过 classMetadataStore 和固定的 DECORATED_KEYS_KEY 实现
|
|
37
|
-
const DECORATED_KEYS_KEY = Symbol.for("imean:decoratedKeys");
|
|
38
|
-
// 存储在 classMetadataStore 中:classMetadataStore.get(class).get(DECORATED_KEYS_KEY) -> Set<symbol>
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
- **用途**:记录某个类被哪些装饰器 key 装饰了
|
|
42
|
-
- **存储位置**:存储在 `classMetadataStore` 中,使用固定的 `DECORATED_KEYS_KEY` 作为 key
|
|
43
|
-
- **访问方式**:通过 `getKeysByClass(target)` 获取装饰该类的所有 key
|
|
44
|
-
|
|
45
|
-
#### 3. class + key -> metadata 映射
|
|
46
|
-
|
|
47
|
-
```typescript
|
|
48
|
-
const classMetadataStore = new WeakMap<Class, Map<symbol, any>>();
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
- **用途**:存储真正的元数据
|
|
52
|
-
- **存储结构**:
|
|
53
|
-
- key: 类构造函数
|
|
54
|
-
- value: Map<symbol, any>
|
|
55
|
-
- `DECORATED_KEYS_KEY` -> `Set<symbol>`(记录该类被哪些 key 装饰)
|
|
56
|
-
- 其他 key -> 实际的元数据对象
|
|
57
|
-
- **访问方式**:通过 `getClassMetadata(target, key)` 获取元数据
|
|
58
|
-
|
|
59
|
-
### 双向映射维护机制
|
|
60
|
-
|
|
61
|
-
当装饰器应用到类上时,系统会自动维护双向映射:
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
function registerKeyClassRelation(targetClass: Class, metadataKey: symbol): void {
|
|
65
|
-
// 1. 在类上记录这个 key(class -> keys)
|
|
66
|
-
const decoratedKeys = getOrCreateDecoratedKeysSet(targetClass);
|
|
67
|
-
decoratedKeys.add(metadataKey);
|
|
68
|
-
|
|
69
|
-
// 2. 在 keyToClassesMap 中记录这个类(key -> classes)
|
|
70
|
-
if (!keyToClassesMap.has(metadataKey)) {
|
|
71
|
-
keyToClassesMap.set(metadataKey, new Set());
|
|
72
|
-
}
|
|
73
|
-
keyToClassesMap.get(metadataKey)!.add(targetClass);
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### 设计优势
|
|
78
|
-
|
|
79
|
-
1. **双向访问**:
|
|
80
|
-
- 通过 key 可以找到所有被装饰的类(无需知道类名)
|
|
81
|
-
- 通过类可以找到所有装饰它的 key(了解类的装饰情况)
|
|
82
|
-
|
|
83
|
-
2. **元数据存储分离**:
|
|
84
|
-
- 映射关系存储在全局 Map 和类上的固定 key
|
|
85
|
-
- 真正的元数据存储在类上,通过 key 访问
|
|
86
|
-
|
|
87
|
-
3. **内存安全**:
|
|
88
|
-
- 使用 WeakMap 存储类相关的数据,避免内存泄漏
|
|
89
|
-
- keyToClassesMap 使用普通 Map,但只存储类引用,不阻止垃圾回收
|
|
90
|
-
|
|
91
|
-
### 使用场景示例
|
|
92
|
-
|
|
93
|
-
#### 场景 1:通过 key 查找所有被装饰的类
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
const Module = createClassDecorator();
|
|
97
|
-
const key = Symbol.for("imean:classMetadata");
|
|
98
|
-
|
|
99
|
-
@Module({ name: "user-module" })
|
|
100
|
-
class UserService {}
|
|
101
|
-
|
|
102
|
-
@Module({ name: "order-module" })
|
|
103
|
-
class OrderService {}
|
|
104
|
-
|
|
105
|
-
// 无需知道类名,直接通过 key 查找所有模块
|
|
106
|
-
const allModules = getClassesByKey(key);
|
|
107
|
-
// Set { UserService, OrderService }
|
|
108
|
-
|
|
109
|
-
// 遍历所有模块并获取元数据
|
|
110
|
-
for (const ModuleClass of allModules) {
|
|
111
|
-
const metadata = getClassMetadata(ModuleClass, key);
|
|
112
|
-
console.log(metadata.name); // "user-module", "order-module"
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
#### 场景 2:查看类被哪些装饰器装饰
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
const Module = createClassDecorator();
|
|
120
|
-
const Config = createClassDecorator(Symbol.for("config"));
|
|
121
|
-
const Cache = createClassDecorator(Symbol.for("cache"));
|
|
122
|
-
|
|
123
|
-
@Module({ name: "test" })
|
|
124
|
-
@Config({ env: "prod" })
|
|
125
|
-
@Cache({ ttl: 60 })
|
|
126
|
-
class TestService {}
|
|
127
|
-
|
|
128
|
-
// 查看类被哪些装饰器装饰
|
|
129
|
-
const keys = getKeysByClass(TestService);
|
|
130
|
-
// Set { Symbol(imean:classMetadata), Symbol(config), Symbol(cache) }
|
|
131
|
-
|
|
132
|
-
// 遍历所有 key 并获取对应的元数据
|
|
133
|
-
for (const key of keys) {
|
|
134
|
-
const metadata = getClassMetadata(TestService, key);
|
|
135
|
-
console.log(key.toString(), metadata);
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## API
|
|
140
|
-
|
|
141
|
-
### 创建装饰器
|
|
142
|
-
|
|
143
|
-
#### `createClassDecorator(metadataKey?)`
|
|
144
|
-
|
|
145
|
-
创建类装饰器工厂函数。
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
import { createClassDecorator } from "./metadata/metadata";
|
|
149
|
-
|
|
150
|
-
const Module = createClassDecorator();
|
|
151
|
-
|
|
152
|
-
@Module({ name: "user-module", version: "1.0.0" })
|
|
153
|
-
class UserService {}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
#### `createMethodDecorator(metadataKey?)`
|
|
157
|
-
|
|
158
|
-
创建方法装饰器工厂函数。
|
|
159
|
-
|
|
160
|
-
```typescript
|
|
161
|
-
import { createMethodDecorator } from "./metadata/metadata";
|
|
162
|
-
|
|
163
|
-
const Handler = createMethodDecorator();
|
|
164
|
-
|
|
165
|
-
class UserService {
|
|
166
|
-
@Handler({ type: "route", options: { method: "GET" } })
|
|
167
|
-
getUser() {}
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### 双向访问 API(新功能)
|
|
172
|
-
|
|
173
|
-
#### `getClassesByKey(metadataKey)`
|
|
174
|
-
|
|
175
|
-
通过装饰器 key 获取所有被装饰的类。
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
import { getClassesByKey } from "./metadata/metadata";
|
|
179
|
-
|
|
180
|
-
const key = Symbol.for("imean:classMetadata");
|
|
181
|
-
const classes = getClassesByKey(key);
|
|
182
|
-
// Set { UserService, OrderService, ... }
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
#### `getKeysByClass(target)`
|
|
186
|
-
|
|
187
|
-
获取类被哪些装饰器 key 装饰了。
|
|
188
|
-
|
|
189
|
-
```typescript
|
|
190
|
-
import { getKeysByClass } from "./metadata/metadata";
|
|
191
|
-
|
|
192
|
-
const keys = getKeysByClass(UserService);
|
|
193
|
-
// Set { Symbol(imean:classMetadata), Symbol(config), ... }
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### 读取元数据
|
|
197
|
-
|
|
198
|
-
#### `getClassMetadata(target, metadataKey?)`
|
|
199
|
-
|
|
200
|
-
获取类的元数据。
|
|
201
|
-
|
|
202
|
-
```typescript
|
|
203
|
-
import { getClassMetadata } from "./metadata/metadata";
|
|
204
|
-
|
|
205
|
-
const metadata = getClassMetadata(UserService);
|
|
206
|
-
console.log(metadata.name); // 'user-module'
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
#### `getMethodMetadata(target, methodName, metadataKey?)`
|
|
210
|
-
|
|
211
|
-
获取方法的元数据列表。
|
|
212
|
-
|
|
213
|
-
```typescript
|
|
214
|
-
import { getMethodMetadata } from "./metadata/metadata";
|
|
215
|
-
|
|
216
|
-
const metadataList = getMethodMetadata(UserService, "getUser");
|
|
217
|
-
console.log(metadataList); // [{ type: 'route', options: {...} }]
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
#### `getAllMethodMetadata(target, metadataKey?)`
|
|
221
|
-
|
|
222
|
-
获取类的所有方法元数据。
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
import { getAllMethodMetadata } from "./metadata/metadata";
|
|
226
|
-
|
|
227
|
-
const allMetadata = getAllMethodMetadata(UserService);
|
|
228
|
-
// Map<string, MethodMetadataItem[]>
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### 检查元数据
|
|
232
|
-
|
|
233
|
-
#### `hasClassMetadata(target, metadataKey?)`
|
|
234
|
-
|
|
235
|
-
检查类是否有元数据。
|
|
236
|
-
|
|
237
|
-
#### `hasMethodMetadata(target, methodName, metadataKey?)`
|
|
238
|
-
|
|
239
|
-
检查方法是否有元数据。
|
|
240
|
-
|
|
241
|
-
## 使用示例
|
|
242
|
-
|
|
243
|
-
### 基础用法
|
|
244
|
-
|
|
245
|
-
```typescript
|
|
246
|
-
import { createClassDecorator, createMethodDecorator } from "./metadata/metadata";
|
|
247
|
-
|
|
248
|
-
// 创建装饰器
|
|
249
|
-
const Module = createClassDecorator();
|
|
250
|
-
const Handler = createMethodDecorator();
|
|
251
|
-
|
|
252
|
-
// 使用装饰器
|
|
253
|
-
@Module({ name: "user-service" })
|
|
254
|
-
class UserService {
|
|
255
|
-
@Handler({ type: "route", options: { method: "GET" } })
|
|
256
|
-
getUser() {
|
|
257
|
-
return { id: 1 };
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// 读取元数据
|
|
262
|
-
import { getClassMetadata, getMethodMetadata } from "./metadata/metadata";
|
|
263
|
-
|
|
264
|
-
const classMeta = getClassMetadata(UserService);
|
|
265
|
-
const methodMeta = getMethodMetadata(UserService, "getUser");
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### 双向访问示例
|
|
269
|
-
|
|
270
|
-
```typescript
|
|
271
|
-
import {
|
|
272
|
-
createClassDecorator,
|
|
273
|
-
getClassesByKey,
|
|
274
|
-
getKeysByClass,
|
|
275
|
-
getClassMetadata,
|
|
276
|
-
} from "./metadata/metadata";
|
|
277
|
-
|
|
278
|
-
const Module = createClassDecorator();
|
|
279
|
-
const key = Symbol.for("imean:classMetadata");
|
|
280
|
-
|
|
281
|
-
@Module({ name: "user-module" })
|
|
282
|
-
class UserService {}
|
|
283
|
-
|
|
284
|
-
@Module({ name: "order-module" })
|
|
285
|
-
class OrderService {}
|
|
286
|
-
|
|
287
|
-
// 方式 1:通过 key 查找所有被装饰的类
|
|
288
|
-
const allModules = getClassesByKey(key);
|
|
289
|
-
console.log(allModules.size); // 2
|
|
290
|
-
|
|
291
|
-
// 遍历所有模块
|
|
292
|
-
for (const ModuleClass of allModules) {
|
|
293
|
-
const metadata = getClassMetadata(ModuleClass, key);
|
|
294
|
-
console.log(metadata.name);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// 方式 2:查看类被哪些装饰器装饰
|
|
298
|
-
const keys = getKeysByClass(UserService);
|
|
299
|
-
console.log(keys.has(key)); // true
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
### 自定义元数据键
|
|
303
|
-
|
|
304
|
-
```typescript
|
|
305
|
-
import { createMethodDecorator } from "./metadata/metadata";
|
|
306
|
-
|
|
307
|
-
const CUSTOM_KEY = Symbol.for("my-custom-key");
|
|
308
|
-
const Handler = createMethodDecorator(CUSTOM_KEY);
|
|
309
|
-
|
|
310
|
-
class Service {
|
|
311
|
-
@Handler({ type: "custom" })
|
|
312
|
-
method() {}
|
|
313
|
-
}
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
### 多装饰器应用
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
const Handler = createMethodDecorator();
|
|
320
|
-
|
|
321
|
-
class Service {
|
|
322
|
-
// 同一方法可以被多个装饰器标注
|
|
323
|
-
@Handler({ type: "route", options: { method: "GET" } })
|
|
324
|
-
@Handler({ type: "cache", options: { ttl: 60 } })
|
|
325
|
-
@Handler({ type: "auth", options: { required: true } })
|
|
326
|
-
getUser() {}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// 读取时会返回所有元数据
|
|
330
|
-
const metadata = getMethodMetadata(Service, "getUser");
|
|
331
|
-
// [{ type: 'route', ... }, { type: 'cache', ... }, { type: 'auth', ... }]
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
## 与 reflect-metadata 的区别
|
|
335
|
-
|
|
336
|
-
| 特性 | reflect-metadata | metadata.ts |
|
|
337
|
-
| -------- | ------------------------ | ---------------------- |
|
|
338
|
-
| 标准 | 实验性装饰器 | Stage 3 装饰器 |
|
|
339
|
-
| 依赖 | 需要包 | 无依赖 |
|
|
340
|
-
| API | `Reflect.defineMetadata` | `createClassDecorator` |
|
|
341
|
-
| 性能 | 运行时反射 | 直接属性访问 |
|
|
342
|
-
| 类型安全 | 部分 | 完全 |
|
|
343
|
-
| 双向访问 | 不支持 | ✅ 支持 |
|
|
344
|
-
|
|
345
|
-
## 设计原则
|
|
346
|
-
|
|
347
|
-
1. **简单够用**:只提供必要的功能,不包含业务逻辑
|
|
348
|
-
2. **类型安全**:完整的 TypeScript 类型支持
|
|
349
|
-
3. **无依赖**:不依赖任何外部库
|
|
350
|
-
4. **标准化**:使用最新的装饰器标准
|
|
351
|
-
5. **双向访问**:支持通过 key 查找类,通过类查找 key
|
|
352
|
-
|
|
353
|
-
## 在框架中的使用
|
|
354
|
-
|
|
355
|
-
框架使用此工具库来实现:
|
|
356
|
-
|
|
357
|
-
- `Handler` 装饰器:基于 `createMethodDecorator`
|
|
358
|
-
- `Module` 装饰器:基于 `createClassDecorator`
|
|
359
|
-
- 元数据读取:使用 `getMethodMetadata` 和 `getAllMethodMetadata`
|
|
360
|
-
- **类发现**:使用 `getClassesByKey` 查找所有被装饰的类(无需知道类名)
|
|
361
|
-
|
|
362
|
-
这样的设计使得装饰器功能与框架业务逻辑完全解耦,可以独立使用或替换。
|
|
363
|
-
|
|
364
|
-
## 数据流图
|
|
365
|
-
|
|
366
|
-
```
|
|
367
|
-
装饰器应用流程:
|
|
368
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
369
|
-
│ @Module({ name: "user-module" }) │
|
|
370
|
-
│ class UserService {} │
|
|
371
|
-
└─────────────────────────────────────────────────────────────┘
|
|
372
|
-
│
|
|
373
|
-
▼
|
|
374
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
375
|
-
│ registerKeyClassRelation(UserService, key) │
|
|
376
|
-
└─────────────────────────────────────────────────────────────┘
|
|
377
|
-
│
|
|
378
|
-
┌───────────┴───────────┐
|
|
379
|
-
▼ ▼
|
|
380
|
-
┌───────────────────┐ ┌───────────────────┐
|
|
381
|
-
│ keyToClassesMap │ │ classMetadataStore│
|
|
382
|
-
│ key -> Set<Class> │ │ class -> Map<...> │
|
|
383
|
-
│ │ │ DECORATED_KEYS │
|
|
384
|
-
│ key: { │ │ KEY -> Set<key> │
|
|
385
|
-
│ UserService │ │ key -> metadata │
|
|
386
|
-
│ } │ │ } │
|
|
387
|
-
└───────────────────┘ └───────────────────┘
|
|
388
|
-
│ │
|
|
389
|
-
│ │
|
|
390
|
-
▼ ▼
|
|
391
|
-
┌───────────────────┐ ┌───────────────────┐
|
|
392
|
-
│ getClassesByKey() │ │ getKeysByClass() │
|
|
393
|
-
│ 通过 key 找类 │ │ 通过类找 key │
|
|
394
|
-
└───────────────────┘ └───────────────────┘
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
## 实现细节
|
|
398
|
-
|
|
399
|
-
### 1. 装饰器应用时的处理
|
|
400
|
-
|
|
401
|
-
当装饰器应用到类上时,`createClassDecorator` 会:
|
|
402
|
-
|
|
403
|
-
1. 调用 `registerKeyClassRelation` 注册双向映射
|
|
404
|
-
2. 将元数据存储到 `classMetadataStore` 中
|
|
405
|
-
|
|
406
|
-
### 2. 方法装饰器的处理
|
|
407
|
-
|
|
408
|
-
方法装饰器也会在类上注册 key,这样可以通过 `getKeysByClass` 找到所有装饰该类的 key(包括类装饰器和方法装饰器的 key)。
|
|
409
|
-
|
|
410
|
-
### 3. 内存管理
|
|
411
|
-
|
|
412
|
-
- `classMetadataStore` 和 `methodMetadataStore` 使用 WeakMap,不会阻止垃圾回收
|
|
413
|
-
- `keyToClassesMap` 使用普通 Map,但只存储类引用,类被回收后引用会失效(虽然 Set 中仍保留引用,但不影响功能)
|
|
414
|
-
- 如果需要完全清理,可以考虑添加清理函数(当前版本暂未实现)
|
|
415
|
-
|
|
416
|
-
## 注意事项
|
|
417
|
-
|
|
418
|
-
1. **keyToClassesMap 的内存**:使用普通 Map 而非 WeakMap,因为需要能够遍历所有被装饰的类。如果类被回收,Map 中的引用会变成"僵尸引用",但不影响功能。
|
|
419
|
-
|
|
420
|
-
2. **装饰器执行时机**:装饰器在类定义时执行,但 `addInitializer` 中的代码在类实例化时执行。因此双向映射的注册发生在类实例化时。
|
|
421
|
-
|
|
422
|
-
3. **方法装饰器**:方法装饰器也会在类上注册 key,这意味着 `getKeysByClass` 会返回包括方法装饰器 key 在内的所有 key。
|