Nest.js系列之Providers及模块功能使用详解
作者:water
提供者
Providers
是Nest
的一个基本概念。提供者是一个大的分类,比如sevice
、repository
、factory
、helper
等都是提供者。可以通过constructor
注入依赖关系。对象之间可以创建各种关系。提供者只是一个用@Injectable()
装饰的类
在控制器的文章中,知道了如何创建一个简单的控制器,控制器中不应该包含过多的复杂任务处理逻辑,这部分的任务逻辑处理应该交给Providers
因为Nest可以面向对象的方式设计和组织依赖性,所以强烈建议遵循SOLID原则
什么是SOLID原则
SOLID 原则其实是用来指导软件设计的,它一共分为五条设计原则,分别是:
- 单一职责原则(SRP)
- 开闭原则(OCP)
- 里氏替换原则(LSP)
- 接口隔离原则(ISP)
- 依赖倒置原则(DIP)
服务
从创建一个简单的服务开始,服务由控制器使用,服务其实也是一个提供者
import { Injectable } from '@nestjs/common'; import { User } from './interfaces/user.interface'; @Injectable() export class UsersService { private readonly users: User[] = []; create(user: User) { this.users.push(user); } findAll(): User[] { return this.users; } }
之前文章提到过可以使用命令快速创建一个服务 nest g service users
控制器中如何使用服务
import { Controller, Get, Post, Body } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { UsersService } from './users.service'; import { User } from './interfaces/user.interface'; @Controller('users') export class CatsController { constructor(private usersService: UsersService) {} @Post() async create(@Body() createUserDto: CreateUserDto) { this.usersService.create(createUserDto); } @Get() async findAll(): Promise<User[]> { return this.usersService.findAll(); } }
通过实例可以看出,控制器如果想要使用服务,只需要将服务通过依赖注入的方式注入到控制器中
constructor(private usersService: UsersService) {}
依赖注入
Nest 是建立在强大的设计模式,通常称为依赖注入。我们建议在官方的 Angular文档中阅读有关此概念的精彩文章。
在 Nest
中,借助 TypeScript 功能,管理依赖项非常容易,因为它们仅按类型进行解析。在下面的示例中,Nest
将 catsService
通过创建并返回一个实例来解析 CatsService
(或者,在单例的正常情况下,如果现有实例已在其他地方请求,则返回现有实例)。解析此依赖关系并将其传递给控制器的构造函数(或分配给指定的属性):
constructor(private readonly catsService: CatsService) {}
注册提供者
现在我们已经定义了提供者(UsersService
),并且已经有了该服务的使用者(UsersController
),我们需要在 Nest
中注册该服务,以便它可以执行注入。 为此,我们可以编辑模块文件(app.module.ts
),然后将服务添加到@Module()
装饰器的 providers
数组中。
import { Module } from '@nestjs/common'; import { UsersController } from './users/users.controller'; import { UsersService } from './users/users.service'; @Module({ controllers: [UsersController], providers: [UsersService], }) export class AppModule {}
小结
提供者可以简单理解为是服务,但是毕竟服务只是一种提供者。在nest中通过使用服务来做逻辑处理。
模块
什么是模块
模块是具有@Module()装饰器的类,Nest使用模块来组织代码
每个nest程序至少有一个模块,也就是根模块。但是这是对于小应用来说的,对于大型程序来说,会拥有多个模块,每个模块拥有自己的功能。 @Module()装饰器接受属性对象
- providers 由nest注入器实例化的提供者,并且可以至少在整个模块中共享
- controllers 必须创建的控制器
- imports 导入模块的列表,这些模块导出了此模块中所需要的提供者
- exports 本模块导出的可以用于其他模块的提供者
默认情况下,该模块封装提供程序。这意味着无法注入既不是当前模块的直接组成部分,也不是从导入的模块导出的提供程序。因此,您可以将从模块导出的提供程序视为模块的公共接口或API。
功能模块
通常来说,一个功能对应一个模块,比如UsersController
和UsersService
应该属于一个模块,该模块就称为功能模块
users/users.module.ts
import { Module } from '@nestjs/common'; import { UsersController } from './users.controller'; import { UsersService } from './users.service'; @Module({ controllers: [UsersController], providers: [UsersService], }) export class UsersModule {}
可以使用cli命令来创建一个模块
nest g module cats
当写好一个功能模块之后,要把模块导入到根模块
import {Module} from '@nestjs/common'; import {UsersModule} from './users/users.module'; @Module({ imports: [CatsModule], }) export class ApplocationModule {}
共享模块
nest默认情况下,模块是单例,因此可以很轻松的在多个模块之间共享同一个提供者实例
其实在nest中,每个模块都是共享模块,可以被任意模块重复使用。但是如果要在几个模块共享某一个服务,比如UsersService,那就需要在它所属的模块中导出这个服务,放到exports数组中
import { Module } from '@nestjs/common'; import { UsersController } from './users.controller'; import { UsersService } from './users.service'; @Module({ controllers: [UsersController], providers: [UsersService], exports: [UsersService] }) export class UsersModule {}
每个导入UsersModule
的模块都可以访问UsersService
模块的导出与导入
模块不仅可以导出提供者,而且还可以导出自己导入的模块
@Module({ imports: [CommonModule], exports: [CommonModule], }) export class CoreModule {}
依赖注入
提供者也可以注入到模块中
import { Module } from '@nestjs/common'; import { UsersController } from './cats.controller'; import { UsersService } from './cats.service'; @Module({ controllers: [CatsController], providers: [CatsService], }) export class CatsModule { constructor(private readonly catsService: CatsService) {} }
全局模块
有时候需要在任何地方导入相同的模块,如果每个模块都导入,就会很繁琐,所以就有了全局模块
import { Module, Global } from '@nestjs/common'; import { UsersController } from './users.controller'; import { UsersService } from './users.service'; @Global() @Module({ controllers: [UsersController], providers: [UsersService], exports: [UsersService], }) export class UsersModule {}
@Global
装饰器使模块成为全局作用域。 全局模块应该只注册一次,最好由根或核心模块注册。 在上面的例子中,CatsService
组件将无处不在,而想要使用 CatsService
的模块则不需要在 imports
数组中导入 CatsModule
。
使一切全局化并不是一个好的解决方案。 全局模块可用于减少必要模板文件的数量。 imports
数组仍然是使模块 API 透明的最佳方式。
动态模块
Nest
模块系统包括一个称为动态模块的强大功能。此功能使您可以轻松创建可自定义的模块,这些模块可以动态注册和配置提供程序。动态模块在这里广泛介绍。在本章中,我们将简要概述以完成模块介绍。
以下是一个动态模块定义的示例 DatabaseModule
:
import { Module, DynamicModule } from '@nestjs/common'; import { createDatabaseProviders } from './database.providers'; import { Connection } from './connection.provider'; @Module({ providers: [Connection], }) export class DatabaseModule { static forRoot(entities = [], options?): DynamicModule { const providers = createDatabaseProviders(options, entities); return { module: DatabaseModule, providers: providers, exports: providers, }; } }Copy to clipboardErrorCopied
forRoot()
可以同步或异步(Promise
)返回动态模块。
此模块 Connection
默认情况下(在 @Module()
装饰器元数据中)定义提供程序,但此外-根据传递给方法的 entities
和 options
对象 forRoot()
-公开提供程序的集合,例如存储库。请注意,动态模块返回的属性扩展(而不是覆盖)@Module()
装饰器中定义的基本模块元数据。这就是从模块导出静态声明的 Connection
提供程序和动态生成的存储库提供程序的方式。
如果要在全局范围内注册动态模块,请将 global
属性设置为 true
。
{ global: true, module: DatabaseModule, providers: providers, exports: providers, }Copy to clipboardErrorCopied
如上所述,将所有内容全局化不是一个好的设计决策。
所述 DatabaseModule
可以被导入,并且被配置以下列方式:
import { Module } from '@nestjs/common'; import { DatabaseModule } from './database/database.module'; import { User } from './users/entities/user.entity'; @Module({ imports: [DatabaseModule.forRoot([User])], }) export class AppModule {}Copy to clipboardErrorCopied
如果要依次重新导出动态模块,则可以 forRoot()
在导出数组中省略方法调用:
import { Module } from '@nestjs/common'; import { DatabaseModule } from './database/database.module'; import { User } from './users/entities/user.entity'; @Module({ imports: [DatabaseModule.forRoot([User])], exports: [DatabaseModule], }) export class AppModule {}
总结
模块就是一个功能的聚合,nest用模块化来组织程序。
以上就是Nest.js系列之Providers及模块功能使用详解的详细内容,更多关于Nest.js Providers模块功能的资料请关注脚本之家其它相关文章!