响应式的web服务器,当RX遇上Spring——Spring 5新特性之响应式Web应用

原标题:当RX遇上Spring——Spring 5新特性之响应式Web应用

介 绍

1.1 何谓响应式编程?

简单来说,响应式编程讲的就是让应用变得异步、事件驱动,而且仅需少量线程就能在同一个JVM上垂直扩展而无需通过集群方式水平扩展。

响应式应用的一个关键特征就是背压。所谓背压就是一种保护消费者不被生产者的过度生产压垮的机制。举例来说,假如有一连串的从数据库一直延伸到HTTP响应的响应式组件,在HTTP链接太慢的情况下,数据仓储也会相应降低速度,或是在网络容量恢复前彻底停止工作。

响应式编程也使得编程范式从命令式向声明式的异步逻辑组合变迁。打个比方,命令式好比一个代码块来执行任务,声明式就是用Java 8的CompletableFuture通过lambda表达式来构建下一步的操作。

更全面的介绍参见Dave Syer的博客”Notes on Reactive Programming”。

1.2 响应式API与重要组建

Spring Framework 5用ReactiveStreams作为异步组件以及库之间的交流协议。Reactive Streams是业内协作共同构建的规格。Java 9也采用了Reactive Streams,并命名为java.util.concurrent.Flow。

Spring Framework内部采用Reactor来支持响应式编程。ReactiveStreams在实现Reactor时用Flux和Mono 这两个组合式API扩展了基本的Publisher协议,分别提供了对0..N以及0..1的数据序列的声明式操作的支持。

Spring框架在滋生的许多响应式API中同样暴露了Flux和Mono接口。在应用层,用户也可以选择使用Spring提供的对RxJava的全面支持。

更多响应式类型参见Sebastien Deleuze的”understanding Reactive Types”。

Spring Web响应式模块

Spring Framework 5包括了全新的spring-web-reactive模块。该模块提供了响应式HTTP以及WebSocket客户端的支持。在响应式Web应用服务器上也支持REST,HTML浏览器以及WebSocket类型的交互。

2.1 服务器端

服务器端支持两种不同的编程模型:

基于注解(包括@Controller以及其他Spring MVC支持的注解)

函数式(Java 8 lambda式的路由以及处理)

两种编程模型都是基于吧非阻塞HTTP运行时转化为Reactive Steams API。下图展示了服务器端技术栈。左边是传统的基于Servlet的Spring MVC(spring-web-mvc)以及右边的响应式技术栈(spring-web-reactive)。

330fa012510f4a65fb8bc1f28190dd22.png

全新的响应式技术栈能和运行在支持Servlet 3.1非阻塞IO API的Servlet容器之上,也能运行在诸如Netty活Undertow的异步运行时之上。所有的运行时都被包装秤响应式的ServerHttpRequest以及ServerHttpResponse,请求和响应体被表示为有背压支持的Flux而不是InputStream和OutputStream。Flux不仅支持REST风格的JSON和XML序列化和反序列化,也支持HTML视图渲染以及Server-Sent Events。

基于注解的编程模型:

Spring MVC 中的@Controller编程模式在响应式模式下同样得到支持。主要区别就是其使用的底层框架协议。在响应式模式下,HandlerMapping和HandlerAdaper是非阻塞的,而且工作在ServerHttpRequest和ServerHttpResponse之上,而不是传统的HttpServletRequest和HttpServletResponse之上。

例如这个响应式控制器:

@RestControllerpublicclass PersonController { privatefinalPersonRepository repository; publicPersonController(PersonRepository repository) { this.repository= repository; } @PostMapping("/person") Mono create(@RequestBody Publisher personStream) { returnthis.repository.save(personStream).then(); } @GetMapping("/person") Flux list() { returnthis.repository.findAll(); } @GetMapping("/person/{id}") Mono findById(@PathVariable String id) { returnthis.repository.findOne(id); }}

函数式模型:

函数式模型用Java 8 lambda风格的撸起以及请求响应。主要的API是函数式接口RouterFunction和HandlerFunction。他们是创建Web应用简单又强大的工具。

函数式请求响应参见下例:

PersonRepository repository = ...RouterFunctions .route(GET("/person/{id}").and(accept(APPLICATION_JSON)), request -> { int personId = Integer.valueOf(request.pathVariable("id")); Mono notFound = ServerResponse.notFound().build(); return repository.findOne(personId) .then(person -> ServerResponse.ok().body(Mono.just(person), Person.class)) .otherwiseIfEmpty(notFound); }) .andRoute(GET("/person").and(accept(APPLICATION_JSON)), request -> ServerResponse.ok().body(repository.findAll(), Person.class)) .andRoute(POST("/person").and(contentType(APPLICATION_JSON)), request -> ServerResponse.ok().build(repository.save(request.bodyToMono(Person.class))));

更多详情参见M3 release blog post

2.2 客户端

Spring Framework 5提供了一个函数式、响应式的WebClient。WebClient是

RestTemplate的全面的非阻塞、响应式的替代解决方案。他爸网络输入输出暴露为ClientHttpRequest和ClientHttpResponse,请求体和响应体为Flux。响应与服务器端,json, xml, sse的序列化在WebClient上也都有响应支持。WebClient需要一个ClientHttpConnector实例来诸如特定的HTTP客户端。

下例使用了Reactor Nettty:

WebClient client = WebClient.create(new ReactorClientHttpConnector());ClientRequest request = ClientRequest .GET("http://example.com/accounts/{id}", 1L) .accept(APPLICATION_JSON) .build();

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值