介绍完Spring Boot所提供的针对响应式Web服务的功能特性,接下来,让我们看看在应用程序中如何充分利用这些功能特性。
使用非阻塞式Web服务提升系统性能一直以来,SpringWebMVC是我们开发Web服务的主流框架。
但要注意的是,尽管Servlet本身在新版本中提供了异步非阻塞的通信机制,但SpringWebMVC在实现上并不允许在整个请求的生命周期中都采用非阻塞式的操作方式。
因此,Spring在尽量沿用原有的开发模式以及API设计的基础上提供了支持异步非阻塞的Spring WebFlux框架。WebMVC和WebFlux的本质区别在于它们对请求的处理模型不同。
我们知道,WebMVC建立在阻塞I/O之上。
这意味着处理每个请求的Thread可能被从I/O读取传入消息体阻塞。相比之下,WebFlux构建在非阻塞API之上,这意味着没有操作需要与I/O阻塞线程进行交互。
通过简单的原理分析,我们明确了使用WebFlux所提供的非阻塞式Web服务能够提高系统的性能。为了验证这一分析结果,我们可以通过执行测试用例来提供量化指标和数据。这里直接引用《Spring响应式编程》一书中的测试结果,图5-7展示了WebFlux与WebMVC吞吐量测量结果。
图5-7 WebFlux与WebMVC吞吐量测量结果比较
而图5-8则展示了WebFlux和WebMVC的延迟对比结果。
图5-8 WebFlux和WebMVC的延迟对比
在图5-7和图5-8中,“ ”线代表WebMVC,“-”线代表WebFlux。通过对比,我们不难得出结论,WebFlux在降低吞吐量和减少系统延迟方面比WebMVC更高效。具体的测试结果可以进一步参考《Spring响应式编程》。
构建全栈响应式服务体系针对响应式编程技术栈,有一点需要注意,即响应式编程并不是只针对系统中的某一部分组件,而是要适用于调用链路上的所有组件。所谓的全栈响应式编程,具体指的是响应式开发方式的有效性取决于是否在整个请求链路的各个环节都采用了响应式编程模型,如图5-9所示。
图5-9 全栈响应式编程示意图
在图5-9中,如果某一个环节或步骤不是响应式的,就会出现同步阻塞,从而导致响应式数据流无法正常运作。如果某一层组件(例如数据访问层)无法采用响应式编程模型,那么响应式编程的概念对于整个请求链路的其他层而言就没有意义。
本章关注的是Web服务和网络协议。事实上,从Spring Boot 2开始,对于支持响应式访问的各种数据库,Spring Data都提供了响应式版本的Repository。
目前,Spring Data Reactive Repository支持MongoDB、Cassandra、Redis、Couchbase等多款主流的NoSQL数据库。Spring Data项目有几个单独的模块,逐个对这些NoSQL数据库提供了响应式的数据访问支持。
我们在前面的案例中,已经看到了针对MongoDB的ReactiveMongoRepository。在使用方式上,响应式Spring Data Repository和普通的Repository是完全一致的。
这里特别强调一点,在常见的Web服务架构中,最典型的非响应式场景就是在数据访问层中使用关系型数据库。对关系型数据访问过程的响应式改造一直是技术难点,但Spring Data团队还是做出了很多尝试工作,并最终开发了R2DBC规范。
R2DBC是Reactive Relational DataBase Connectivity的简称,即响应式关系数据库连接。
该规范允许驱动程序提供与数据库的完全响应式和非阻塞集成。
Spring Data同样采用了R2DBC规范,并孵化了另一个独立组件SpringData R2DBC。图5-10展示了JDBC规范与R2DBC规范的对应关系以及所涉及的技术栈。
图5-10 Spring Data JDBC和Spring Data R2DBC
类似地,这里也给出一个使用Spring Data R2DBC的示例代码,如代码清单5-43所示。
代码清单5-43 扩展R2dbcRepository接口实现代码
public interface ReactiveUserRepository extends R2dbcRepository<User,
Long> {
@Query("insert into USER (USER_CODE, USER_NAME) values
(:userCode,:userName)")
Mono<Boolean> addUser(String userCode, String userName);
@Query("SELECT * FROM USER WHERE id =:id")
Mono<User> getUserById(Long id);
}
可以看到,ReactiveUserRepository扩展了Spring Data R2DBC所提供的R2dbcRepository接口,然后使用@Query注解分别定义了一个查询和插入方法。
RSocket替代HTTP在Java领域中,RSocket协议的应用越来越广泛。Spring Boot、SpringCloud以及Dubbo等主流开发框架都集成了RSocket协议。
Dubbo在3.0.0-SNAPSHOT版本基于RSocket协议对响应式编程提供了支持,用户可以非常方便地使用RSocket的语法。对Spring家族而言,Spring 5.2也把RSocket作为内置的通信协议,而随着Spring Boot 2.4的发布,Spring对RSocket的支持日渐完善。
一定程度上,可以把RSocket看作对HTTP等其他协议的一种替代。REST的最大特点是它与HTTP强关联,这是优势也是劣势。优势在于基于RESTful风格开发的Web API易于调试,而劣势在于其交互模式过于单一,只支持请求-响应式。在微服务大行其道的当下,RSocket专为服务交互而设计。它是一种面向连接的消息驱动协议,在应用程序级别内置了数据流控制机制。它既可以在浏览器中使用,也可以在服务器上使用。
响应式Web面试题分析面试题1:响应式编程模型和普通编程模型的本质区别是什么?
答案:本质上,我们认为普通编程模型执行的是一种同步阻塞式的操作,而响应式编程模型则为开发人员提供了异步非阻塞式的编程体验。这个说法在面试过程中是没有问题的,但显然比较单薄和缺乏个人见解。我们可以从数据流的角度切入来看待这个问题。在传统的方法调用中,客户端和服务器端之间的数据流向是一种“拉”模式,即服务端被动接收客户端请求并返回数据。与之对应的,如果数据主动从服务器端流向客户端,那么就是一种“推”模式。而从响应式流规范的定义来看,我们可以明确响应式编程介于这两者之间,是一种推-拉结合的数据流模式,从而避免出现纯拉模式下的系统瓶颈,以及纯推模式下的流量控制问题。这样的回答思路和方式在面试过程中更加能够获取面试官的认同。
面试题2:你能描述响应式编程技术的具体应用场景吗?
答案:响应式编程的异步非阻塞式特性在日常开发过程中有广泛的应用场景。首先就是数据流处理,典型的案例包括日志埋点、服务运行时的状态采集等。其次,我们在高并发场景中也可以使用响应式编程技术,因为响应式编程所具备的异步非阻塞式I/O模型非常适合对并发流量进行高效处理。针对这个面试题,我们可以列举响应式编程的具体应用案例,像NetflixHystrix就使用RxJava来实现了滑动窗口机制,从而高效完成了对服务调用结果的分析和统计;而Spring家族自建的Spring Cloud Gateway则使用ProjectReactor实现了响应式API网关。
面试题3:Spring框架为开发人员提供了哪些响应式编程组件?
答案:这道题基本属于送分题,你只要对Spring 5框架有基本的了解,相信都能应答自如,毕竟响应式编程是该框架引入的最大的功能特性。
Spring 5分别针对Web服务层和数据访问层提供了WebFlux和Reactive SpringData框架。而Reactive Spring Data框架则对MongoDB、Cassandra、Redis、Couchbase等多款主流的NoSQL数据库提供了响应式编程支持。
面试题4:Spring WebFlux和传统的WebMVC在架构上有什么区别和联系?
答案:从架构设计上讲,Spring作为一套集成性和扩展性很强的开源框架,针对不同的Web层组件,尽量采用了相同的组件命名和实现策略。例如,在WebFlux和WebMVC中,都存在HandlerMapping和HandlerAdapter等同名的编程组件。开发人员也可以使用传统的@RestController、@RequestMapping等注解来同时开发基于WebMVC和WebFlux的Web服务。这是两者之间的联系。
而区别也很明确,主要体现在对请求的处理模型上。本章专门对两者处理模型的原理和效果做了深入分析,你可以参考文中的描述来进行回答。
面试题5:为什么要引入RSocket协议,和HTTP相比该协议有哪些优势?
答案:这道题考查你在新技术上的知识面广度。RSocket是一款2015年才出现的网络通信协议,和HTTP相比还很年轻,但却有取而代之的趋势。原因就在于HTTP本身的请求-响应式交互过程过于单一,无法满足多样化的请求处理场景。而RSocket则提供了额外的请求-响应流、即发-即忘和通道这三种新的交互模式,并且能够与响应式编程技术完美整合。因此,无论是交互方式上还是性能上,它都比HTTP更有优势。
面试题6:所谓全栈式响应式技术体系指的是什么?通过Spring框架我们如何做到全栈响应式?
答案:围绕响应式编程模型,我们需要明确全栈响应式编程这一概念,其背后的设计思想就是请求从Web服务层到业务逻辑层再到数据访问层,整个调用链路中都应该以响应式数据流的方式进行交互,也就是说方法调用返回值都应该是Mono或Flux对象。在Spring中,普通的业务逻辑层组件可以直接使用Project Reactor框架来集成响应式编程技术,针对Web服务开发可以使用WebFlux,针对网络通信可以使用Spring RSocket,而针对数据访问则可以使用Reactive Spring Data。特别需要强调一下的是,当下关系型数据库仍然是大多数业务系统的基石,而针对关系型数据库访问,Spring也专门开发了Spring Data R2DBC框架。
本文给大家讲解的内容是springweb服务应用响应式Web开发组件:响应式Web实战经验- 下文给大家讲解的是springboot内置缓存:打造高性能系统缓存,缓存注解