前言
大家好啊,这里是想要创业的李卢。最近在学习NestJS的过程中,对Provider的概念总是模糊不清,于是在经过两天的资料查询后,作者总结出了自己对Provider的见解。
前排提示:作者也是Nest新手,如果有错误的地方,欢迎指正,大家一起友好讨论~
话不多说,我们开始吧
Provider 提供者
Provider是NestJS中的核心概念,是NestJs依赖注入系统的基础。在NestJS中几乎所有的事物都可以被视为Provider。
再进一步了解Provider之前,我们需要先了解一下Controller、Service和Module这三个构件的功能
Controller
Controller负责处理传入的HTTP请求、返回Response给客户端。Controller通常是后端交互的入口。在Controller中定义了路由,并通过装饰器指明各种HTTP操作,如Get、Post、Put等
总的来说Controller处理三个方面的事情:
- 路由:Controller管理特定的路由请求,处理特定URL的Get、Post请求等
- 请求处理:Controller直接与HTTP层交互,负责接受请求、处理请求和返回响应
- 委托:Controller通常不直接执行业务逻辑,而是将业务逻辑的处理委托给后端的Service
import { Controller, Get } from "@nestjs/common"
import { MyService } from "./myService.service"
//处理对 服务域名/user 的请求
@Controller("user")
export class UserController{
//构造函数注入MyService雷
constructor(private readonly myService: MyService){}
@Get()
getHello():string {
//将Get请求具体的处理委托给MyService去做
return this.myService.getHello()
}
}
Service
Service在NestJS中通常被用来封装业务逻辑、数据处理、与数据库交互等操作。Service可以被多个Controller复用,减少重复代码,简化逻辑修改
总的来说Service负责三件事:
- 复用性:一个Service可以被多个Controller复用
- 分离关注点:将业务逻辑从Conroller中分离,让Controller专注于HTTP层的交互
- 独立性:Service可以使代码独立于网络层,进行单元测试
import { Injectable } from "@nestjs/common"
Injectable()
export class MySerivce{
getHello(){
return "Hello Wrold"
}
}
Module
将项目分为若干个模块,每一个模块负责特定的业务或工作,这个模块就是Module。在Module里面封装了相关的Controller和Service。每一个模块可以在不同项目中复用
总的来说,Module主要做三件事:
- 封装:封装特定业务的Controller和Service
- 解耦:每一个模块负责一个业务,将大型业务分解成各个模块
- 依赖注入:Module定义了Provider的作用域,负责依赖注入的正确配置
import { Module } from "@nestjs/common"
import { ExampleController } from "./example.controller"
import { ExampleService } from "./example.service"
@Module({
controllers: [ExampleController],
providers: [ExampleService],
})
export class ExampleModule {}
Provider与Controller、Service和Module的关系
那么什么是Provider呢?已知:
- Controller负责HTTP层的通信和路由,然后将具体的问题交给Service去实现
- Service负责编写逻辑代码
- Module负责将项目分为各个模块,封装模块里的Controller和Service 那么Provider是为了解决什么问题呢?
Provider主要作用是封装代码,实现简单方便的复用
假如是,我们想要封装一个类、一个函数、一个异步操作,我们就可以将这个类看作Provider,用@Injectable()去装饰这个类,然后在Module里面注册Provider。
这样一来,就可以在该Module里的Controller和Service中简单方便的复用这个类
看到这里,你是不是觉得Provider和Service很像?
- Service用来编写逻辑代码,然后在Controller中使用。
- Service编写的代码需要在Module里注册,然后再在Controller中使用
没有错,其实Service就是一个Provider,是一个封装类的Provider。
Provider是Service的超集
下面我们就以注册、使用Service的流程,进一步了解Provider
注册Provider
假设我们有一个用户类,这个用户类有两个方法:
- 增加用户
- 获得用户
class user{
private users:string[] = []
consturctor(){}
add(name: string){
this.users.push(name)
return name
}
getAll(){
return this.users
}
}
我们将要将这个类抽象成一个Service,为此我们需要做四件事:
- 取一个更语义化的类名
- 使用
@Injectable()装饰 - 设置类可导出
- 在Module里进行配置 让我们先完成前三项:
//导入@Injectable装饰器
import { Injectable } from "@nestjs/common"
//用装饰器装饰类
@Injectable()
//将类设置为导出,取一个更加语义化的类名
export class UserService{
private users:string[] = []
consturctor(){}
add(name: string){
this.users.push(name)
return name
}
getAll(){
return this.users
}
}
接下来我们开始Module配置: 假设我们有一个UserModule文件,作为User业务的Module。 为了将我们的UserServce类注册为Provider,实现在Controller和其他Service内的复用,我们需要做以下三件事:
- 导入
@Module装饰器工厂函数- 向工厂函数传入配置对象,在配置对象中注册我们的封装UserService类
- 导入需要注册为Provider的类,函数等
- 导出Module类,方便复用
import { Module } from "@nestjs/common"
import { UserService } from "./userService"
//Module是一个装饰器工厂函数,传入参数,返回一个装饰器
@Module({
//配置对象的provider属性用来注册,将需要注册的类放入数组里
provider: [UserSrvice]
})
//导出Module类,方便复用
export class UsersModule{}
在Controller中使用Provider
在上面的例子中,我们定义了UserService类,并且将其注册成了一个Provider。同时这个UserService类也是一个Service,因为Provider是Service的超集。
接下来,我们来学习,如何在Controller中使用注册后的Provider,我们需要三步完成这个工作:
- 在Controller中导入注册后的Provider
- 将该Provider在Controller类的构造函数中,作为参数传入
- 在Controller类的方法中,通过this访问到Provider,使用Provider上的方法等
假设我们以及有了一个UserController文件,在没有使用Provider之前是这样的:
import { Controller, Get, Post, Body } from '@nestjs/common';
@Controller('users')
export class UsersController {
constructor() {}
@Get()
getAllUsers() {
//获取所有用户
}
@Post()
addUser(@Body() user) {
//添加新用户
}
}
现在我们按照这三步,在Controler中使用Provider
import { Controller, Get, Post, Body } from '@nestjs/common';
//导入在Module注册后的Provider
import { UserService } from './user.service';
@Controller('users')
export class UsersController {
//在Controler的注册函数中,将Provider作为参数传入
constructor(private userService: UserService) {}
@Get()
getAllUsers() {
//使用时,直接通过this访问到Provider,然后调用Provider上的方法
return this.userService.findAll();
}
@Post()
addUser(@Body() user) {
return this.userService.add(user);
}
}
总结
总的来说,Provider的作用是为了实现代码的复用。Provider可以封装类、函数等,Provider是Service的超集,Provider包含Service,Service一定是Provider,Provider如果封装的是类,那么这个Provider大概率也是Service。