0

我是一名长期学习 NestJS 的 Spring 开发人员。相似之处是如此惊人,我很喜欢这让我变得如此富有成效。然而,一些文档让我对一件事感到困惑。

我尝试将 Nest“提供者”比作具有默认范围的 Spring bean。例如,我创建了@Injectable 服务类,并将它们视为类似于 Spring @Services。因此,我假设这些服务类需要是线程安全的 - 没有状态等。但是,这里的 Nest 文档对我来说有点模棱两可,并且暗示这可能没有必要(强调我的):

对于来自不同编程语言背景的人来说,在 Nest 中得知几乎所有内容都是在传入请求之间共享的,这可能是出乎意料的。我们有一个到数据库的连接池、具有全局状态的单例服务等。请记住,Node.js 不遵循请求/响应多线程无状态模型,其中每个请求都由单独的线程处理。因此,使用单例实例对我们的应用程序来说是完全安全的。

如果单个请求没有在它们自己的线程中处理,Nest 提供程序是否可以包含可变状态?由应用程序确保每个传入请求都以“干净的状态”开始 - 例如,使用 NestInterceptor 初始化该状态。但对我来说,该文档读取提供者是作为单例创建的,因此可以用作类似于数据包装容器的东西,例如 Java 中的 ThreadLocal。

我读错了吗,或者这是 Nest 和 Spring 之间的行为差​​异?

4

1 回答 1

2

你真的应该使请求处理无状态。

我对 Spring 一无所知,但在 NestJS(以及一般的异步 javascript)中,它是单线程的,但不会阻塞 I/O。这意味着同一个服务实例的同一个线程可以一次处理多个请求。它一次只能做一件事,但它可以在前一件事等待数据库查询、请求完成传输、外部服务响应或文件系统时开始执行下一件事传递文件的内容等

因此,在一个线程中,使用一个服务实例,可能会发生这种情况:

  • 请求 A 进来。
  • 为请求 A 分派数据库查询。
  • 请求 B 进来。
  • 为请求 B 分派数据库查询。
  • 请求 A 的数据库查询返回,并发送响应。
  • 请求 B 的数据库查询返回,并发送响应。

这对状态意味着它将在请求之间共享。如果您的服务在异步操作的一个步骤中设置了一个实例属性,那么另一个异步操作可能会在第一个操作完成之前开始,并为该实例属性设置一个新值,这可能不是您想要的。

我相信 Nest 文档提到的“全局状态”不是每个请求,而是一般配置状态。就像外部服务的 URL 或数据库的凭据一样。


还值得一提的是,控制器会收到一个请求对象,它代表该特定请求。向该请求对象添加属性是很常见的,例如当前经过身份验证的用户。请求对象可以传递给你的控制器和服务上下文,这种方式对这个架构很友好。

于 2021-04-17T08:52:38.307 回答