Appearance
前言
上班中碰到需要写@Sub @Pub的来实现在不同节点发布订阅事件,仔细看了官方的源码
动态注册Module最佳方案
- 使用useValue将options注入到Service中
ts
// Config.module.ts
import { ConfigService } from './config.service.ts'
@Module({})
export class ConfigModule {
static register(options) {
return {
module: ConfigModule,
providers: [
{
provide: "CONFIG_OPTIONS",
useValue: options
},
ConfigService
],
}
}
}
// config.service.ts
@Injectable()
export class ConfigService {
constructor(@Inject('CONFIG_OPTIONS') options) {
//
}
}- 使用ConfigurableModuleBuilder构建动态模块
ts
const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = new ConfigurableModuleBuilder<ConfigModuleOptions>().setExtra({
isGlobal: true
}, (def, extra) =>({
...def,
global: extra
})).build()
@Module({
providers: [ConfigService],
})
export class SomeModule extends ConfigurableModuleClass {}依赖的socpe,scope的冒泡性,冒泡性的使用场景
依赖有3种scope,全局单例,请求单例和瞬时。默认是全局单例,通过contextId实现请求单例。每次请求时会创建一个contextId,后续会根据contextId检索请求单例。瞬时是每次注入时都创建一个新的示例,特别注意是注入时才创建,比如在多个service中注入时,每个service 会创建一次。
依赖的冒泡性
如果一个依赖是请求,那么引入的这个依赖的服务也会冒泡变成请求。所以需要注意对 请求范围提供者的注入,可能会导致整个controller变成请求范围
依赖的分组
对于请求范围的依赖注入,每次请求都会创建实例,如果能够对同一个用户所有的请求共享实例,或者多个用户共享实例。需要用到依赖分组
- 首先标记请求,制定什么是常见的请求,什么是特殊需要分组的请求。
ts
export class AggregateByTenantContextIdStrategy implements ContextIdStrategy {
attach(contextId: ContextId, request: Request) {
const tenantId = request.headers['x-tenant-id'] as string;
let tenantSubTreeId: ContextId;
if (tenants.has(tenantId)) {
tenantSubTreeId = tenants.get(tenantId);
} else {
tenantSubTreeId = ContextIdFactory.create();
tenants.set(tenantId, tenantSubTreeId);
}
// If tree is not durable, return the original "contextId" object
return (info: HostComponentInfo) =>
info.isTreeDurable ? tenantSubTreeId : contextId;
}
}- 对依赖进行标记,添加durable: true,将依赖提升成分组依赖
分组依赖也是具有冒泡性,如果一个依赖是分组依赖, 依赖该依赖的服务也会分组。
ModuleRef
注入当前module,可以获取当前模块中的依赖,通过token手动注入依赖或者全局依赖。
ModuleRef.get 和 ModuleRef.resolve
获取module中依赖,前者获取单例,后者获取请求范围或者瞬时单例, 通过相同的ContextId 可以保证创建相同的依赖。
ModuleRef.create
直接创建依赖
Module.registerRequestByContextId
注册一个请求,把请求和contextId绑定,用于后续的@Req 等。
discoverService 发现服务
查询所有已经注册的service和controller,通过DiscoveryService.createDecorator 创建的装饰器,还能被快速的查询。
ts
export const FeatureFlag = DiscoveryService.createDecorator();
this.discoveryService.getMetadataByDecorator(FeatureFlag, item)必须掌握的生命周期
传入请求
中间件
- 全局绑定的中间件
- 模块绑定中间件
卫兵
- 全局守卫
- 控制器守卫
- 路由守卫
拦截器(预控制器)
- 全局拦截器
- 控制器拦截器
- 路由拦截器
管道
- 全局管道
- 控制器管道
- 管道布线
- 路由参数管道
控制器(方法处理程序)
服务(如果存在)
拦截器(请求后)
- 路由拦截器
- 控制器拦截器
- 全局拦截器
异常过滤器
- 路线
- 控制器
- 全球
服务器响应
持久提供程序
Reflecor如何发现元数据,和原生的metadata定义有什么好处。
DI 树和 DI子树
按照模块划分子树
MetadataScanner 用法
已经被reflector 取代,开发者不需要关注
