Spring5响应式编程

响应式编程管理需要以非阻塞方式对该数据作出响应的数据和消费者的生产者之间的异步数据流。所以,

Reactive Programming就是关于非阻塞应用程序,这些应用程序是异步和事件驱动的,并且需要少量的线程来扩展。

基于线程的框架难以构建响应式应用程序,因为基于共享可变状态,线程和锁定扩展应用程序涉及高度复杂性。

在Reactive Programming上下文中,“一切都是流,当流中有数据时,以非阻塞方式运行”。

1. 为什么使用响应式编程

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

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

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

对于一个或几个线程,IO绑定任务可以以异步和非阻塞方式执行,而不阻塞当前线程。

响应式编程可以更有效地进行管理,在高交互和实时应用程序或任何操作/事件时,都可能触发多个连接子系统的通知。

2. 响应式编程的理想应用场景

大量的交易处理服务,如银行部门。

大型在线购物应用程序的通知服务,如淘宝。

股票价格同时变动的股票交易业务。

3. Reactive Streams

“响应流”定义了一个API规范,其中包含一组最小的接口,这些接口公开定义了非阻塞反压力的数据流的操作和实体的方法。

随着反压的引入,Reactive Streams允许用户控制发布者的数据交换速率。

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

Reactive Streams主要用作互操作层

4. Spring 5用于响应编程工作

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

Spring-Web-Reactive模块和Spring MVC共享许多常用算法,但Spring-Web-Reactive模块已经重新定义了许多Spring MVC契约,如HandlerMapping和HandlerAdapter,以使它们成为异步和非阻塞以及启用被动HTTP请求和响应(以RouterFunction和HandlerFunction的形式)。

除了现有的RestTemplate外,Spring5中还推出了新的响应式WebClient。

支持响应式编程的HTTP客户端(例如Reactor,Netty,Undertow)已适应一系列响应式ClientHttpRequest和ClientHttpResponse抽象,将请求和响应主体公开为Flux ,并在读取和写入方面提供完全反压支持。

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

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

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

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

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

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

6. Spring Web Reactive与Spring Web MVC

Spring 5同时提供了Spring Web Reactive(在spring-web-reactive模块下)和Spring Web MVC(在spring-webmvc模块下)。

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

Spring MVC执行需要Servlet容器,而Spring Web Reactive也可以在非Servlet上运行,例如Netty和Undertow。

如果一定要求使用Java 8 lambda或使用Kotlin轻量级功能性Web框架的非阻塞Web栈,则应考虑从Spring MVC应用程序切换到Spring Web Reactive。

7. 响应式编程的基本配置

这里是pom.xml,2.0.0的M5版本和WebFlux的依赖。

< parent >
 < groupId > org.springframework.boot  groupId >
 < artifactId > spring-boot-starter-parent  artifactId >
 < version > 2.0.0.M5  version >
 parent >
< dependencies >
 < dependency >
 < groupId > org.springframework.boot  groupId >
 < artifactId > spring-boot-starter-webflux  artifactId >   dependency >
 dependencies >

8. 传统方法与响应式方法

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

@GetMapping("/traditional")
public List < Product > getAllProducts() {
 System.out.println("traditional 开始执行...");
 List < Product > products = prodService.getProducts("traditional");
 System.out.println("traditional 执行完成");
 return products;
}

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

@GetMapping(value = "/reactive", .TEXT_EVENT_STREAM_VALUE)
public Flux < Product > getAll() {
 System.out.println("使用Flux响应式请求开始执行");
 Flux < Product > fluxProducts = prodService.getProductsStream("Flux");
 System.out.println("使用Flux响应式请求完成");
 return fluxProducts;
}

9. 响应式Web客户端

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

ClientHttpRequest和ClientHttpResponse抽象将请求和响应主体公开为Flux ,并在读和写方面提供完全反压支持。

Spring Core的编码器和解码器抽象也用于客户端,用于将Flux的字节序列化到输入和输出对象。

以下是一个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)));
}

10. Spring5的局限性

  • 一个响应式应用程序故障排除有点困难,并且有可能在修复一个问题时,你可能意外地阻塞了已经引入的代码。

  • 大多数传统的基于Java的集成库仍然阻塞。

  • 有限的可供选择的响应数据库,除了少数的NoSQL数据库(如MongoDB)外。

  • 不支持Spring Security。


分享到:


相關文章: