NestJs的Provider和Service傻傻分不清?这篇文章讲清楚!Provider教程

483 阅读5分钟

前言

大家好啊,这里是想要创业的李卢。最近在学习NestJS的过程中,对Provider的概念总是模糊不清,于是在经过两天的资料查询后,作者总结出了自己对Provider的见解。

前排提示:作者也是Nest新手,如果有错误的地方,欢迎指正,大家一起友好讨论~

话不多说,我们开始吧

462faa1075aaf20b69bc5f303c5c61b9.jpg

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。