## 模块参考
Nest提供了一个`ModuleRef`类来导航到内部提供者列表,并使用注入令牌作为查找键名来获取一个引用。`ModuleRef`类也提供了一个动态实例化静态和范围的提供者的方法。`ModuleRef`可以通过常规方法注入到类中:
>cats.service.ts
```typescript
@Injectable()
export class CatsService {
constructor(private moduleRef: ModuleRef) {}
}
```
> `ModuleRef`从`@nestjs/core`中引入。
### 获取实例
`ModuleRef`实例(下文称为**模块引用**) 拥有`get()`方法。该方法获取一个提供者,控制器或者通过注入令牌/类名获取一个在当前模块中可注入对象(例如守卫或拦截器等)。
>cats.service.ts
```typescript
@Injectable()
export class CatsService implements OnModuleInit {
private service: Service;
constructor(private moduleRef: ModuleRef) {}
onModuleInit() {
this.service = this.moduleRef.get(Service);
}
}
```
> 不能通过`get()`方法获取一个范围的提供者(暂态的或者请求范围的)。要使用下列的技术,参考[这里](https://docs.nestjs.com/fundamentals/injection-scopes)了解更多控制范围。
要从全局上下文获取一个提供者(例如,如果提供者在不同模块中注入),向`get()`的第二个参数传递`{ strict: false }`选项。
```typescript
this.moduleRef.get(Service, { strict: false });
```
### 处理范围提供者
要动态处理一个范围提供者(瞬态的或请求范围的),使用`resolve()`方法并将提供者的注入令牌作为参数提供给方法。
>cats.service.ts
```typescript
@Injectable()
export class CatsService implements OnModuleInit {
private transientService: TransientService;
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
this.transientService = await this.moduleRef.resolve(TransientService);
}
}
```
`resolve()`方法从其自身的注入容器树返回一个提供者的唯一实例。每个子树都有一个独一无二的上下文引用。因此如果你调用该方法一次以上并进行引用比较的话,结果是不同的。
>cats.service.ts
```typescript
@Injectable()
export class CatsService implements OnModuleInit {
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
const transientServices = await Promise.all([
this.moduleRef.resolve(TransientService),
this.moduleRef.resolve(TransientService),
]);
console.log(transientServices[0] === transientServices[1]); // false
}
}
```
要在不同的`resolve()`调用之间产生一个单例,并保证他们共享同样生成的DI容器子树,向`resolve()`方法传递一个上下文引用,使用`ContextIdFactory`类来生成上下文引用。该类提供了一个`create()`方法,返回一个合适的独一无二的引用。
>cats.service.ts
```typescript
@Injectable()
export class CatsService implements OnModuleInit {
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
const contextId = ContextIdFactory.create();
const transientServices = await Promise.all([
this.moduleRef.resolve(TransientService, contextId),
this.moduleRef.resolve(TransientService, contextId),
]);
console.log(transientServices[0] === transientServices[1]); // true
}
}
```
> `ContextIdFactory`类从`@nestjs/core`包中引入。
### 注册`REQUEST`提供者
手动生成的上下文标识符(带)表示提供程序所在`ContextIdFactory.create()`的 DI 子树,因为它们不是由 Nest 依赖注入系统实例化和管理的。`REQUEST``undefined`
`REQUEST`为手动创建的 DI 子树注册自定义对象,使用`ModuleRef#registerRequestByContextId()`方法如下:
```typescript
const contextId = ContextIdFactory.create();
this.moduleRef.registerRequestByContextId(/* YOUR_REQUEST_OBJECT */, contextId);
```
### 获取当前子树
**有时,也需要在请求上下文**中获取一个请求范围提供者的实例。例如,`CatsService`是请求范围的,要获取的`CatsRepository`实例也被标识为请求范围。要分享同一个注入容器子树,你需要获取当前上下文引用而不是生成一个新的(像前面的`ContextIdFactory.create()`函数)。使用`@Inject()`来获取当前的请求对象。
>cats.service.ts
```typescript
@Injectable()
export class CatsService {
constructor(
@Inject(REQUEST) private request: Record<string, unknown>,
) {}
}
```
> 从[这里](https://docs.nestjs.com/fundamentals/injection-scopes#request-provider)了解更多请求提供者
使用`ContextIdFactory`类的`getByRequest()`方法来基于请求对象创建一个上下文id 并传递`resolve()`调用:
```typescript
const contextId = ContextIdFactory.getByRequest(this.request);
const catsRepository = await this.moduleRef.resolve(CatsRepository, contextId);
```
### 动态实例化自定义类
要动态实例化一个之前未注册的类作为提供者,使用模块引用的`create()`方法。
> cats.service.ts
```typescript
@Injectable()
export class CatsService implements OnModuleInit {
private catsFactory: CatsFactory;
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
this.catsFactory = await this.moduleRef.create(CatsFactory);
}
}
```
该技术允许你在框架容器之外偶然实例化一个不同的类。
- 介绍
- 概述
- 第一步
- 控制器
- 提供者
- 模块
- 中间件
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 自定义装饰器
- 基础知识
- 自定义提供者
- 异步提供者
- 动态模块
- 注入作用域
- 循环依赖
- 模块参考
- 懒加载模块
- 应用上下文
- 生命周期事件
- 跨平台
- 测试
- 技术
- 数据库
- Mongo
- 配置
- 验证
- 缓存
- 序列化
- 版本控制
- 定时任务
- 队列
- 日志
- Cookies
- 事件
- 压缩
- 文件上传
- 流式处理文件
- HTTP模块
- Session(会话)
- MVC
- 性能(Fastify)
- 服务器端事件发送
- 安全
- 认证(Authentication)
- 授权(Authorization)
- 加密和散列
- Helmet
- CORS(跨域请求)
- CSRF保护
- 限速
- GraphQL
- 快速开始
- 解析器(resolvers)
- 变更(Mutations)
- 订阅(Subscriptions)
- 标量(Scalars)
- 指令(directives)
- 接口(Interfaces)
- 联合类型
- 枚举(Enums)
- 字段中间件
- 映射类型
- 插件
- 复杂性
- 扩展
- CLI插件
- 生成SDL
- 其他功能
- 联合服务
- 迁移指南
- Websocket
- 网关
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 适配器
- 微服务
- 概述
- Redis
- MQTT
- NATS
- RabbitMQ
- Kafka
- gRPC
- 自定义传输器
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 独立应用
- Cli
- 概述
- 工作空间
- 库
- 用法
- 脚本
- Openapi
- 介绍
- 类型和参数
- 操作
- 安全
- 映射类型
- 装饰器
- CLI插件
- 其他特性
- 迁移指南
- 秘籍
- CRUD 生成器
- 热重载
- MikroORM
- TypeORM
- Mongoose
- 序列化
- 路由模块
- Swagger
- 健康检查
- CQRS
- 文档
- Prisma
- 静态服务
- Nest Commander
- 问答
- Serverless
- HTTP 适配器
- 全局路由前缀
- 混合应用
- HTTPS 和多服务器
- 请求生命周期
- 常见错误
- 实例
- 迁移指南
- 发现
- 谁在使用Nest?