近年来,由于响应式编程能够以声明性的方式(而不是强制性的)构建应用程序,从而在响应程序和弹性方面具有更强的响应能力,因此在开发人员社区和客户中日益流行。Spring 5 Reactive Systems纳入其核心框架的事实表明,范式已向声明式编程转移。

响应式编程管理数据生产者与需要以非阻塞方式对数据做出反应的使用者之间的异步数据流。因此,响应式编程全部与异步和事件驱动的非阻塞应用程序有关,这些应用程序需要少量线程来扩展。

由于基于共享的可变状态,线程和锁扩展应用程序存在很高的复杂性,因此很难使用基于线程的框架来构建反应性应用程序。

在响应式编程上下文中,“一切都是流,并且当流中有数据时,一切都以非阻塞的方式进行。”这篇分享至优锐课学习笔记的文章和大家浅谈一下Spring 5 的响应式编程。


为什么响应式编程

响应式编程的高度抽象性提高了代码的可读性,因此开发人员可以主要关注定义业务逻辑的事件的相互依赖性。

反应模式自然适合高度并发环境中的消息处理,这是企业常见的用例。

具有强制背压的功能,响应式方法最适合控制生产者和消费者之间的流量,这将有助于避免内存不足的问题。

响应式编程可以更有效地管理高度互动和实时的应用程序或任何动作/事件可能触发多个连接子系统的通知的情况。


实现响应式编程的理想用例

·         大量交易处理服务,例如银行业。

·         大型在线购物应用程序(例如Amazon)的通知服务。

·         股票交易同时变化的股票交易业务。


响应式流

“响应流”定义了一个API规范,该规范包含一组最少的接口,这些接口公开了用于定义具有非阻塞背压的异步数据流的操作和实体的方法。

引入反压后,反应流允许订户控制发布者的数据交换速率。

Reactive Streams API作为java.util.concurrent.Flow正式成为Java 9的一部分。

响应式流主要用作互操作性层。


Spring 5响应式编程产品

Spring-Web-Reactive模块和Spring MVC都支持相同的@Controller编程,但是Spring-Web-Reactive另外在Reactive和非阻塞引擎上执行。

Spring-Web-Reactive模块和Spring MVC共享许多常用算法,但是Spring-Web-Reactive模块已经重新定义了许多Spring MVC合约,例如HandlerMappingHandlerAdapter,以使它们异步和非阻塞并启用 反应性HTTP请求和响应(以RouterFunctionHandlerFunction的形式)。

除了现有的RestTemplate之外,Spring 5中还引入了新的反应式WebClient

支持响应式编程的HTTP客户端(例如ReactorNettyUndertow)已经适应了一组响应式的ClientHttpRequestClientHttpResponse抽象,这些抽象将请求和响应主体公开为Flux ,并且在读取和写入端具有完全的反压支持。

Spring 5 Framework引入了Reactor作为Reactive Streams规范的实现。

Reactor是下一代Reactive库,用于在JVM上构建非阻塞应用程序。

Reactor扩展了基本的Reactive Streams Publisher合同,并定义了FluxMono API类型,以分别对0..N0..1的数据序列提供声明性操作。

Spring Web Reactive利用Servlet 3.1提供的非阻塞I / O并在Servlet 3.1容器上运行。

Spring WebFlux提供了两种编程模型的选择。

1.     带注释的控制器:这些与Spring MVC相同,带有一些Spring-Web模块提供的附加注释。Spring MVCWebFlux控制器都支持Reactive返回类型。此外,WebFlux还支持Reactive @RequestBody参数。

2.     函数式编程模型:一个基于lambda的轻量级小型库,它公开实用程序来路由和处理请求。


Spring Web响应式与Spring Web MVC

Spring 5彼此相邻容纳了Spring Web Reactive(在spring-web-reactive模块下)和Spring Web MVC(在spring-webmvc模块下)。

尽管Spring Web ReactiveSpring Web MVC模块都共享许多算法,但是由于Spring Web Reactive能够在Reactive和非阻塞的Reactive Streams HTTP适配器层上运行,因此它们不共享代码。

Spring MVC执行需要Servlet容器,而Spring Web Reactive也可以在非Servlet运行时上运行,例如NettyUndertow

如果绝对需要带有Java 8 lambdaKotlin的轻量级功能性Web框架的无阻塞Web堆栈,则应考虑从Spring MVC应用程序切换到Spring Web Reactive


响应式编程的基本配置

这是带有5.0.0 M5版本和WebFlux依赖项的pom.xml

    org.springframework.boot
    spring-boot-starter-parent
    2.0.0.M5
 
  
    
        org.springframework.boot
        spring-boot-starter-webflux                               
 
  


 

传统方法与反应方法

在传统方法中,执行将被阻止,并将一直等到服务执行完成。在下面的代码中,在第一个打印语句之后,程序执行将被阻塞并等待服务执行完成。服务执行完成后,将恢复程序执行并执行第二个打印语句。

@GetMapping("/traditional")
public List < Product > getAllProducts() {
    System.out.println("Traditional way started");
    List < Product > products = prodService.getProducts("traditional");
    System.out.println("Traditional way completed");
    return products;
}


      

在响应式方法中,程序将继续执行,而无需等待服务执行的完成。 在下面的代码中,在第一个打印语句之后,第二个打印语句将以非阻塞方式执行,而无需等待服务执行完成。将使用产品数据填充Flux流。

@GetMapping(value = "/reactive", .TEXT_EVENT_STREAM_VALUE)
public Flux < Product > getAll() {
    System.out.println("Reactive way using Flux started");
    Flux < Product > fluxProducts = prodService.getProductsStream("Flux");
    System.out.println("Reactive way using Flux completed");
    return fluxProducts;
}


 

响应式Web客户端

除了现有的RestTemplate之外,Spring 5还引入了Reactive WebClient

ClientHttpRequestClientHttpResponse抽象将请求和响应主体公开为Flux ,在读取和写入侧具有完全的反压支持。

来自Spring CoreEncoderDecoder抽象也用于客户端,用于与类型对象之间的字节通量序列化。

以下是一个Reactive WebClient的示例,该示例调用终结点并接收和处理Reactive Stream Flux对象。

@GetMapping("/accounts/{id}/alerts")
public Flux < Alert > getAccountAlerts(@PathVariable Long id) {
    WebClient webClient = new WebClient(new ReactorClientHttpConnector());
    return this.repository.getAccount(id).flatMap(account -> webClient.perform(get("/alerts/{key}", account.getKey())).extract(bodyStream(Alert.class)));
}


 

Spring 5的局限性

·         对响应式应用程序进行故障排除有些困难,并且有可能在解决问题时偶然引入了阻止代码。

·         大多数传统的基于Java的集成库仍处于阻塞状态。

·         除少数NoSQL数据库(例如MongoDB)外,Reactive数据存储区提供有限的选项。

·         仍然不支持Spring Security


感谢你的阅读,希望能让你有所收获~