vlambda博客
学习文章列表

读书笔记《hands-on-reactive-programming-in-spring-5》使用 Spring Boot 2 实现响应式

第 5 章使用 Spring Boot 2 实现响应式

在上一章中,我们学习了 Project Reactor 的基本知识,以及响应式类型和操作符的行为以及它们如何帮助解决不同的业务问题。除了简单的 API 之外,我们还看到,在底层,存在允许并发、异步、非阻塞消息处理的隐藏复杂机制。除此之外,我们还探索了可用的背压控制和相关策略。正如我们在前一章中看到的,Project Reactor 不仅仅是一个反应式编程库。它还提供了附加组件和适配器,即使没有 Spring 框架,也可以构建反应式系统。通过这个,我们看到了 Project Reactor 与 Apache Kafka 和 Netty 的集成。

虽然 Project Reactor 可能在没有 Spring Framework 的情况下运行良好,但通常不足以构建功能丰富的应用程序。这里缺少的元素之一是众所周知的依赖注入,它使我们能够在组件之间解耦。此外,当我们构建强大且可定制的应用程序时,正是 Spring Framework 大放异彩的时候。然而,甚至可以使用 Spring Boot 构建更好的应用程序。

因此,在本章中,我们将描述 Spring Boot 的重要性及其带来的特性。我们还将看到 Spring Framework 5 和 Spring Boot 2 带来的变化,看看 Spring 生态系统如何采用响应式编程方法。

本章涵盖以下主题:

  • The problems Spring Boot solves, and how
  • The essentials of Spring Boot
  • Reactivity in Spring Boot 2.0 and Spring Framework

 

快速启动是成功的关键


人类从不喜欢在与他们的目标无关的日常工作和任务上花费太多时间。在商业中,为了达到预期的结果,我们需要快速学习和快速实验。反应性也适用于现实生活。对市场变化做出反应,快速改变策略,尽快实现新目标至关重要。我们越快证明这个概念,它给企业带来的价值就越大,因此花在研究上的钱就越少。

为此,人类一直致力于简化常规工作。开发人员不被排除在该规则之外。我们喜欢开箱即用的一切,尤其是当我们谈论像 Spring 这样的复杂框架时。尽管 Spring Framework 引入了许多好处和优势特性, 它需要深入了解如何使用它,新手开发人员在涉及到他们没有经验的领域时可能很容易失败。一个简单的控制反转IoC< /span>) 容器的配置,其中至少计算了五种可能的配置方法。为了理解这个问题,让我们看一下下面的代码示例:

publicclassSpringApp{
   publicstaticvoidmain(String[] args){ 
      GenericApplicationContext context = 
         new GenericApplicationContext();

      new XmlBeanDefinitionReader(context)
         .loadBeanDefinitions("services.xml");

      new GroovyBeanDefinitionReader(context)
         .loadBeanDefinitions("services.groovy");

      new PropertiesBeanDefinitionReader(context)
         .loadBeanDefinitions("services.properties");

      context.refresh(); 
   } 
}

从前面的代码中我们可以看出,原始的 Spring Framework 至少有三种不同的方式在 Spring 上下文中注册 bean。

 

一方面,Spring Framework 为我们提供了配置 bean 源的灵活性。另一方面,拥有如此广泛的选项列表会带来一些问题。例如,问题之一是我们 无法轻松调试的 XML 配置。使使用此类配置变得更加困难的另一个问题是 如果没有其他工具(例如 IntelliJ IDEA 或 )无法验证这些配置的正确性 ;弹簧工具套件。最后, 在编码风格和开发约定方面缺乏适当的纪律可能会显着增加大型项目的复杂性并降低其 清晰度。例如,bean 定义的 方法缺乏适当的纪律可能会使未来的项目复杂化,因为团队中的一个单独的开发人员可能会在 XML 中定义 bean,而另一个可能会在属性中这样做。其他任何人都可以在 Java 配置中做同样的事情。因此,新开发人员可能很容易被这种不一致所迷惑,并且钻研项目的时间比必要的时间长得多。

除了简单的 IoC,Spring 框架还提供了更复杂的功能,例如 Spring Web 模块或 Spring Data 模块。这两个模块都需要大量配置才能运行应用程序。当要求开发的应用程序独立于平台时,通常会出现问题,这意味着配置和样板代码的数量越来越多,而与业务相关的代码越来越少。

笔记

请注意,这里 平台无关 意味着独立于特定的服务器 API,例如 Servlet API。或者,它指的是不了解特定环境及其配置以及其他功能。

例如,只需要配置一个简单的 Web 应用程序,我们至少需要 7 行样板代码,如下面的代码所示:

publicclassMyWebApplicationInitializer
             implementsWebApplicationInitializer{      
   @Override
   publicvoidonStartup(ServletContext servletCxt){ 
      AnnotationConfigWebApplicationContext cxt =
new AnnotationConfigWebApplicationContext();
      cxt.register(AppConfig.class);     
      cxt.refresh();
      DispatcherServlet servlet = new DispatcherServlet(cxt);     
      ServletRegistration.Dynamic registration = servletCxt
            .addServlet("app", servlet);
      registration.setLoadOnStartup(1);
      registration.addMapping("/app/*");
   }
}

 

上述 代码 不包括任何安全配置或其他基本功能,例如内容呈现。在某个时间点,每个基于 Spring 的应用程序都有类似的代码,这些代码非常未经优化,需要开发人员额外关注,因此无缘无故地浪费金钱。

使用 Spring Roo 尝试更快地开发应用程序

幸运的是,Spring 团队了解快速启动项目的重要性。 2009 年初,宣布了一个名为 Spring Roo  的新项目(参见 https://projects.spring.io/spring-roo 了解更多详情) 该项目旨在快速应用程序开发。 Spring Roo 背后的 main 理念是使用 convention-over-configuration 方法。为此,Spring Roo 提供了一个命令行用户interface,它可以初始化基础设施和域模型,并创建带有一些命令的 REST API。 Spring Roo 简化了 应用程序开发过程。然而,使用这样的工具进行大型应用程序开发在实践中似乎并不奏效。在这里,当项目结构变得复杂时,或者当使用的技术 超出 Spring框架的范围时,就会出现问题。最后,Spring Roo 在日常使用中也不太流行。因此,快速应用程序开发的问题仍未得到解答。

笔记

请注意 Spring Roo 2.0 版在撰写本文时已发布。这包含许多改进,我们可以在https: //docs.spring.io/spring-roo/docs/current/reference/html

Spring Boot 作为快速增长应用的关键

2012 年底,Mike Youngstrom 提出了一个影响 Spring Framework 未来的问题。 他提出的要点是更改整个 Spring 架构并简化 Spring Framework 的使用,以便开发人员可以更快地开始构建业务逻辑。尽管该提议 被拒绝了,但它还是促使Spring团队创建了一个新项目,大大简化了Spring Framework的使用。 2013 年年中,Spring 团队宣布了第一个名为 Spring Boot 的项目的预发布版本(参见 https://spring.io/projects/spring-boot 了解更多详情)。 Spring Boot 背后的主要思想是简化应用程序开发过程,并允许用户开始一个新项目,而无需任何额外的基础架构配置。

与此同时,Spring Boot 采用了无容器 Web 应用的思想和可执行的 fat JAR 技术。使用这种方法,Spring 应用程序可以在一行上编写并使用一个额外的命令行运行。以下代码展示了一个完整的 Spring Boot Web 应用程序:

@SpringBootApplication
publicclassMyApplication{
   publicstaticvoidmain(String[] args){
      SpringApplication.run(MyApplication.class, args);
   }
}

上述示例中最重要的部分是 有一个名为 @SpringBootApplication 的注解,它是运行 IoC 容器所必需的。还有 MVC 服务器,以及其他应用程序组件。让我们更深入地研究一下。首先,Spring Boot 是现代构建工具(例如 Gradle 或 Maven)的一堆模块和附加组件。一般而言,Spring Boot 有两个它所依赖的核心模块。第一个是 spring-boot模块,它带有与 Spring IoC容器相关的所有可能的默认配置。第二个是spring-boot-autoconfigure, 它为所有现有的Spring项目带来了所有可能的配置,例如Spring Data、Spring MVC、Spring WebFlux等。乍一看,似乎所有定义的配置都立即启用,即使这不是必需的。但是,情况并非如此,在引入特定依赖项之前,所有配置都被禁用。 Spring Boot 为名称中通常包含 单词  -starter- 的模块定义了一个新概念。默认情况下,starters 不包含任何 Java 代码,但会带上所有相关的依赖项来激活 spring-boot-autoconfigure 中的特定配置。有了 Spring Boot,我们现在有了-starter-web 和 -starter-data-jpa 模块,允许配置所有必需的基础设施部件,而无需额外的麻烦。 Spring Roo 项目最显着的区别是其更大的灵活性。除了可以轻松扩展的默认配置外,Spring Boot 还提供了一个流畅的 API 来构建我们自己的启动器。该 API 允许替换默认配置,并为我们提供我们自己的特定模块配置。

笔记

出于本书的目的,我们不涉及 Spring Boot 的细节。然而,Preview Online Code Files Learning Spring Boot 2.0, Second Edition by Greg L. Turnquist 详细介绍了 Spring Boot。我们可以在 https: //www.packtpub.com/application-development/learning-spring-boot-20-second-edition

Spring Boot 2.0 中的响应式


由于这本书是关于响应式编程的,因此我们不会 过多地介绍有关 Spring Boot 的细节。然而,正如上一节所述,快速引导应用程序的能力是成功框架的关键要素。让我们弄清楚反应性是如何反映在 Spring 生态系统中的。由于 only 将编程范式更改为 reactive 编程并没有任何好处,因为 Spring MVC 和 Spring 的阻塞特性数据模块,Spring 团队决定也改变这些模块内部的整个范式。为此,Spring 生态系统为我们带来了一系列反应式模块。在本节中,我们将非常简要地介绍所有这些模块。但是,它们中的大多数将在本书后面的专门章节中介绍。

Spring Core 中的响应式

Spring 生态系统的核心模块是 Spring Core 模块。 Spring Framework 5.x 引入的显着增强之一是对 Reactive 流和响应式库,例如 RxJava 1/2 和 Project Reactor 3。

支持反应类型转换

支持 Reactive Streams 规范的最全面改进之一是引入了ReactiveAdapter< /code> 和 ReactiveAdapterRegistryReactiveAdapter 类提供了两种用于响应式类型转换的基本方法,如下代码所示:

class ReactiveAdapter {
   ...

   <T> Publisher<T> toPublisher(@Nullable Object source) { ... }   // (1)

Object fromPublisher(Publisher<?> publisher) { ... }            // (2)
}

 

 

在前面的例子中,ReactiveAdapter 介绍了两种将任意类型转换为Publisher<T> (用 (1)) 注释并返回到 Object。例如,为了为 RxJava 2 中的 Maybe reactive 类型提供转换,我们可以创建自己的 ReactiveAdapter通过以下方式:

public class MaybeReactiveAdapter extends ReactiveAdapter {        // (1)

public MaybeReactiveAdapter() {                                 // (2)
super(
ReactiveTypeDescriptor                                    // (3)
            .singleOptionalValue(Maybe.class, Maybe::empty),       //
rawMaybe -> ((Maybe<?>)rawMaybe).toFlowable(),            // (4)
publisher -> Flowable.fromPublisher(publisher)            // (5)
                              .singleElement()                     //
      );
}
}

在前面的示例中,我们扩展了默认的 ReactiveAdapter 并提供了自定义实现 (1)。反过来,我们提供了一个默认构造函数并隐藏了它背后的实现细节(2)。父构造函数(3)的第一个参数是 ReactiveTypeDescriptor 实例的定义。

 ReactiveTypeDescriptor 提供了关于 ReactiveAdapter 中使用的反应类型的信息。最后,父构造函数需要定义转换函数(在我们的例子中是 lambdas),将原始对象(假定为 Maybe)转换为 the Publisher (4) 并将任何 Publisher 转换回 也许

笔记

请注意 ReactiveAdapter 假设在将任何对象传递给 toPublisher 方法之前,检查对象的类型兼容性使用 ReactiveAdapter#getReactiveType 方法。

为了简化交互,有 ReactiveAdapterRegistry,它允许我们将 ReactiveAdapter的实例保存在一个地方,如以及概括对它们的访问,如以下代码所示:

ReactiveAdapterRegistry
.getSharedInstance()                                            // (1)
   .registerReactiveType(                                          // (2)
ReactiveTypeDescriptor
         .singleOptionalValue(Maybe.class, Maybe::empty),
rawMaybe -> ((Maybe<?>)rawMaybe).toFlowable(),
publisher -> Flowable.fromPublisher(publisher)
                           .singleElement()
   );

...

ReactiveAdapter maybeAdapter = ReactiveAdapterRegistry
.getSharedInstance()                                            // (1)
   .getAdapter(Maybe.class);                                       // (3)

正如我们所见,ReactiveAdapterRegistry 代表了不同反应类型的 ReactiveAdapter 实例的公共池。反过来,ReactiveAdapterRegistry 提供了一个单例实例 (1),它可以在框架内的许多地方使用或者可以被使用在开发的应用程序中。除此之外,注册表通过提供与上一个示例中相同的参数列表来注册适配器成为可能 (2)。 最后,我们可能会得到一个通过提供应完成转换的 Java 类来实现现有适配器 (3)

反应式 I/O

另一个与 reactive 支持相关的显着改进是核心 I/O 包的增强。首先,Spring Core 模块在 byte instances 的缓冲区上引入了一个额外的抽象,称为 DataBuffer。避免 java.nio.ByteBuffer 的主要原因是提供一个可以支持不同字节缓冲区的抽象,而无需在它们之间进行任何额外的转换。例如,为了将 io.netty.buffer.ByteBuf to ByteBuffer,我们必须访问存储的字节可能需要将它们从堆外空间拉到堆中。这可能会破坏 Netty 提供的有效内存使用和缓冲区回收(重用相同的字节缓冲区)。或者,Spring DataBuffer 提供特定实现的抽象,并允许我们以通用方式使用底层实现。名为 PooledDataBuffer 的附加子接口还支持引用计数功能,并允许开箱即用的高效内存管理。

此外,Spring Core 的第五版引入了一个额外的 DataBufferUtils 类,它允许在反应式流的形式。例如,我们可能会被动地阅读 莎士比亚的哈姆雷特 并通过以下方式提供背压支持:

Flux<DataBuffer> reactiveHamlet = DataBufferUtils
.read(
new DefaultResourceLoader().getResource("hamlet.txt"),
new DefaultDataBufferFactory(),
1024
);

 

我们可能已经注意到, DataBufferUtils.read 返回 DataBuffer 的 Flux 实例。因此,我们可以使用 Reactor 的所有功能来阅读 Hamlet。 

最后,Spring Core 中与 Reactive 相关的最后一个重要且重要的特性是 reactive codecs。反应式编解码器提供了一种将 DataBuffer实例流 转换为对象流并返回的便捷方式。为此,有 Encoder 和 Decoder 接口,它们提供以下编码API/解码数据流:

interface Encoder<T> {
   ...

Flux<DataBuffer> encode(Publisher<? extends T> inputStream, ...);
}

interface Decoder<T> {
   ...

Flux<T> decode(Publisher<DataBuffer> inputStream, ...);

Mono<T> decodeToMono(Publisher<DataBuffer> inputStream, ...);

}

从前面的例子可以看出,这两个接口都使用 Reactive Streams 的 Publisher,并允许对 DataBuffer 的流进行编码/解码 实例到对象。使用这种 API 的主要好处是它提供了一种将序列化数据转换为 Java 对象的非阻塞方式,反之亦然。此外,这种编码/解码数据的方式可以减少处理延迟,因为反应式流的性质允许独立的元素处理,因此我们不必等待最后一个字节开始解码整个数据集。相反,不需要完整的对象列表来开始编码并将它们发送到 I/O 通道,这样两个方向都可以改进。

笔记

要了解有关 Spring Core 中的 Reactive I/O 的更多信息,请访问 https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#databuffers

 

 

总而言之,我们可以说我们在 Spring Framework 中拥有良好的响应式编程基础 Spring Core 第五版。反过来,Spring Boot 将该基础作为骨干组件提供给任何应用程序。它还使得编写响应式应用程序成为可能,同时减少了发明转换响应式类型的方法、以响应式方式使用 I/O 以及即时编码/解码数据的方法。

响应式网络

另一个必须提及的关键点是 Web 模块。首先,Spring Boot 2 引入了一个名为 WebFlux 的新 Web 启动器,它为高吞吐量和低延迟的应用程序带来了新的机会。 Spring WebFlux 模块构建在 Reactive Streams 适配器之上,并提供与 Netty 和 Undertow 等服务器引擎的集成,以及对基于普通 Servlet-API-3.1 的服务器的支持。通过这种方式,Spring WebFlux 提供了非阻塞基础,并为 Reactive Streams 作为业务逻辑代码和服务器引擎之间交互的中央抽象开辟了新的可能性。

笔记

请注意,Servlet API 3.1 的适配器提供了与 WebMVC 适配器不同的纯异步和非阻塞集成。当然,Spring WebMVC 模块也支持 Servlet API 4.0,它启用了 HTTP/2 支持。

反过来,Spring WebFlux 广泛使用 Reactor 3 作为一等公民。正因为如此,我们可以使用开箱即用的响应式编程而无需任何额外的努力,我们还可以在 Project Reactor 与 Netty 的内置集成之上运行 Web 应用程序。最后,WebFlux 模块提供了内置的背压支持,因此我们可以确保 I/O 不会变得不堪重负。除了服务器端交互的变化之外,Spring WebFlux 带来了一个新的 WebClient 类,它可以实现非阻塞 客户端 交互。

此外,除了 WebFlux 模块的引入,旧的 WebMVC 模块也获得了对 Reactive Streams 的一些支持。从 第五版框架开始, Servlet API 3.1 也成为了 WebMVC 模块的基线。这应该意味着 WebMVC 现在 支持 Servlet 规范中提出的形式的非阻塞 I/O。然而, WebMVC 模块的设计在适当级别的非阻塞 I/O 方面并没有太大变化。尽管如此,Servlet 3.0 的异步行为已经 适当地 在那里实现了一段时间。为了填补响应式支持方面的空白,Spring WebMVC 为 ResponseBodyEmitterReturnValueHandler 类提供了升级。由于Publisher 类可能被认为是一个无限的事件流,Emitter 处理程序是放置在不破坏 WebMVC 模块的整个基础架构的情况下进行响应式类型处理的逻辑。为此,WebMVC 模块引入了 ReactiveTypeHandler 类,它负责 正确 处理反应类型,例如Flux< /code> 和 单声道

除了在服务器端支持响应式类型的更改之外,为了在客户端获得非阻塞行为,我们可能会使用从 WebFlux 模块中获取的相同 WebClient 。乍一看,这似乎会导致两个模块之间发生冲突。幸运的是,Spring Boot 提供了一种基于类路径中可用类的复杂环境管理行为。因此,通过提供 WebMVC (spring-boot-starter-web) 模块和 WebFlux,我们得到了 WebMVC 环境和非阻塞响应式 WebClient  来自 WebFlux 模块。

最后,当将两个模块作为反应管道进行比较时,我们得到了下图所示的排列方式:

读书笔记《hands-on-reactive-programming-in-spring-5》使用 Spring Boot 2 实现响应式

图 5.1。管道形式的反应式 WebFlux 和部分反应式 WebMVC 模块的示意图。

从上图中我们可以看出,在使用 WebMVC 或 WebFlux 的两种情况下,我们得到了几乎相同的基于 Reactive Streams 的编程模型。模块之间的显着差异之一是 WebMVC 在与源自旧模块设计的 Servlet API 集成时需要阻塞写入/读取。这个缺陷会导致反应流中的交互模型降级,并将其降级为普通的 PULL 模型。反过来,WebMVC 现在 使用内部专用于所有阻塞读/写的线程池。因此,应适当配置它以避免意外行为。

相比之下, WebFlux 通信模型取决于网络吞吐量和可能定义其自己的控制流的底层传输协议。

总而言之,Spring 5 引入了一个强大的工具,用于使用 Reactive Streams 规范和 Project Reactor 构建反应式、非阻塞应用程序。此外,Spring Boot 支持强大的依赖管理和自动配置,从而保护我们免受依赖地狱的影响。我们不会详细介绍新的 Reactive Web 的功能,但我们将在 第 6 章, WebFlux 异步非阻塞通信。

Spring Data 中的响应式

除了 Web 层的变化之外,大多数 应用程序的另一个重要部分是与存储交互的数据层。多年来,一直在简化日常开发的强大解决方案是 Spring Data 项目,它为通过存储库模式访问数据提供了方便的抽象。从早期开始,Spring Data 主要提供对底层存储区域的同步阻塞访问。幸运的是,第五代 Spring Data 框架为响应式和非阻塞式访问数据库层提供了新的可能性。在新一代中,Spring Data 提供了 ReactiveCrudRepository 接口,它公开了 Project Reactor 的响应式类型,以便与响应式工作流无缝集成。因此,它允许数据库连接器成为完全反应式应用程序的有效部分。

除了响应式存储库,Spring Data 通过扩展 ReactiveCrudRepository 接口提供了几个与存储方法集成的模块。以下是 Spring Data 中现在具有响应式集成的存储 methods 列表:

  • MongoDB via the Spring Data Mongo Reactive module: This is an entirely reactive and nonblocking interaction with the NoSQL database, and it is also a proper backpressure control.
  • Cassandra via the Spring Data Cassandra Reactive module: This is an asynchronous and nonblocking interaction with the Cassandra data storage that supports backpressure over the TCP flow control.
  • Redis via the Spring Data Redis Reactive module: This is a reactive integration with Redis over the Lettuce Java client. 
  • Couchbase via the Spring Data Couchbase Reactive module: This is a reactive Spring Data integration with the Couchbase database over the RxJava-based driver.

此外,所有这些模块都受 Spring Boot 支持,它提供了额外的启动模块,可以与他们选择的存储方法顺利集成。

此外,除了 NoSQL 数据库,Spring Data 还引入了 Spring Data JDBC, 与 JDBC 的轻量级集成,可能很快就会提供反应式 JDBC 连接。反应式数据访问在 第 7 章反应式数据库访问。

综上所述,第五代 Spring Data 完成了从 web 端点到响应式数据库集成的端到端响应式数据流,涵盖了大多数应用程序的需求。反过来,正如我们将在以下部分中看到的那样,其他 Spring Framework 模块的大部分改进都是基于 WebFlux 的响应式功能或响应式 Spring Data 模块。

 

在 Spring Session 中反应

Spring 框架的另一个重大更新,与 Spring Web 模块,是 Spring Session 模块中的响应式支持。 

现在我们获得了对 WebFlux 模块的支持,以便我们可以为会话管理采用有效的抽象。为此,Spring Session 引入了 ReactiveSessionRepository,它可以通过 Reactor 的Mono  实现对存储会话的异步、非阻塞访问。类型。

除此之外,Spring Session 提供与 Redis 的反应式集成,作为反应式 Spring Data 上的会话存储。这样,我们就可以实现一个分布式的WebSession 只需要包含以下依赖即可:

compile "org.springframework.session:spring-session-data-redis"
compile "org.springframework.boot:spring-boot-starter-webflux"
compile "org.springframework.boot:spring-boot-starter-data-redis-reactive"

从前面的 Gradle 依赖示例可以看出,为了实现 Redis 的响应式 WebSession  管理,我们必须将这三个依赖组合到一个地方。反过来,Spring Boot 负责提供精确的 bean 组合并生成合适的自动配置,以便顺利运行 Web 应用程序。

Spring Security 中的响应式

为了强制实施 WebFlux 模块,Spring 5 在 Spring 安全模块中提供了改进的响应式支持。在这里,核心增强是通过 Project Reactor 支持反应式编程模型。我们可能记得,使用旧的Spring Security ThreadLocal 作为 SecurityContext 实例的存储方法。这种技术 在一个线程内执行的情况下效果很好。在任何时候,我们都可以访问 SecurityContext存储在 ThreadLocal storage中。但是,当异步通信生效时,就会出现问题。在这里,我们必须付出额外的努力来将 ThreadLocal 内容转移到另一个Thread,我们为每个Thread 实例之间切换的实例。尽管 Spring Framework 通过使用额外的 简化了SecurityContext 在线程之间的传输ThreadLocal 扩展,在使用 Project Reactor 或类似的响应式库应用响应式编程范例时,我们仍然可能会遇到麻烦。

 

幸运的是,新一代的 Spring Security 采用了 reactor 上下文特性,以便 在 Flux 或 Mono 中传输 安全上下文 stream. 这样,即使在可能在不同执行线程中运行的复杂反应流中,我们也可以安全地访问安全上下文。  第 6 章, WebFlux 异步非阻塞通信。

Spring Cloud 中的响应式

尽管 Spring 云生态系统旨在构建反应式系统使用 Spring Framework,响应式编程范式没有通过 Spring Cloud。首先,这样的变化影响了分布式系统的一个入口点,叫做< strong>gateways. 很长一段时间以来,只有 Spring 模块可以将应用程序作为gateway 是 Spring Cloud Netflix Zuul 模块。我们可能知道,Netflix Zuul 基于使用阻塞同步请求路由的 Servlet API。使进程的请求瘫痪并获得更好性能的唯一方法是通过调整底层服务器线程池。不幸的是,这样的模型不能像响应式方法那样扩展,为什么会发生这种情况的详细信息在 第 6 章中进行了介绍,  WebFlux 异步非阻塞通信

幸运的是,Spring Cloud 引入了新的 Spring Cloud Gateway 模块,该模块构建在 Spring WebFlux 之上并提供异步和非阻塞路由在 Project Reactor 3 的支持下。

笔记

了解更多关于 Spring Cloud Gateway 的信息,请前往 https://cloud .spring.io/spring-cloud-gateway

除了新的 Gateway 模块,Spring Cloud Streams 获得了 Project Reactor 的支持,还引入了更细粒度的流模型。我们将在 第 8 章中介绍 Spring Cloud Streams,使用云扩展流。

最后,为了简化响应式系统的开发,Spring Cloud 引入了一个名为 Spring Cloud Function 的新模块,旨在为构建我们自己的 function as a service< /span> (FaaS) 解决方案。正如我们将在 第 8 章中看到的,使用 Cloud Streams 扩展, Spring Cloud Function 模块不能在没有适当的附加基础设施的情况下用于普通开发。幸运的是,Spring Cloud Data Flow 提供了这种可能性,并且包含了 Spring Cloud Function 的部分功能。 Spring Cloud Function 和 Spring Cloud Data Flow 的细节在此不再赘述,因为它们在 第8章中有介绍, 使用 Cloud Streams 进行扩展。

 

在 Spring 测试中反应

任何系统开发过程的组成部分都是测试。因此,Spring 生态系统提供了改进的 Spring Test 和 Spring 引导测试模块,它扩展了用于测试反应式 Spring 应用程序的附加功能列表。这样,Spring Test 提供了一个 WebTestClient 用于测试基于 WebFlux 的 Web 应用程序,而 Spring Boot Test 使用普通注解来处理测试套件的自动配置。

反过来,为了测试 Reactive Streams 的 Publisher,Project Reactor 提供了 Reactor-Test 模块,结合 Spring Test 和 Spring Boot Test 模块,可以编写 完整的验证套件使用 Reactive Spring 实现的业务逻辑。 所有响应式测试的细节将在 Chapter 9, 测试反应式应用程序。

被动监控

最后,构建在 Project Reactor 和响应式 Spring 框架之上的生产就绪响应式系统应该公开所有重要的操作指标。为此,Spring 生态系统提供了一些具有不同粒度的应用程序监控选项。

首先,Project Reactor 本身具有内置的指标。它提供了Flux#metrics() 方法,可以跟踪反应流中的不同事件。但是,除了手动注册的监控点之外,一个普通的 Web 应用程序还应该跟踪很多内部进程。它还应该以某种方式报告其运营指标。为此,Spring Framework 生态系统提供了更新的 Spring Boot Actuator 模块,该模块支持应用程序监控和故障排除的主要指标。新一代 Spring Actuator 提供与 WebFlux 的完整集成,并使用其异步、非阻塞编程模型来有效地公开度量端点。

Spring Cloud Sleuth 模块提供了监视和跟踪应用程序的最后一个选项,它提供了开箱即用的分布式跟踪。这里一个显着的改进是支持使用 Project Reactor 进行反应式编程,因此应用程序中的所有反应式工作流程都可以正确跟踪。

总而言之,除了核心框架中的响应式改进之外,Spring 生态系统还负责生产就绪的特性,并支持详细的应用程序监控,即使对于响应式解决方案也是如此。所有这些方面都在 第 10 章以及,最后,发布它!

概括


正如我们在本章中所见,引入 Spring Boot 是为了简化 Spring Framework 的开发。它充当 Spring 组件的粘合剂,并根据应用程序依赖关系提供合理的默认配置。在版本 2 中,它还为响应式堆栈提供了出色的支持。本章跳过了有关 Spring 框架改进的许多细节,而是介绍了 Spring Boot 如何帮助我们轻松获得反应式的所有好处。

然而,我们将在接下来的章节中深入探讨 Spring 5.x 中引入的特性和增强功能 从检查 Spring WebFlux 模块开始,并将其与良好的旧 Spring WebMVC 进行比较。