掌握聚合最新动态了解行业最新趋势
API接口,开发服务,免费咨询服务

当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)。

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

基于注解的编程模型:

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

例如这个响应式控制器:

@RestController
publicclass PersonController {

        privatefinalPersonRepository repository;

        publicPersonController(PersonRepository repository) {
               this.repository= repository;
        }

        @PostMapping("/person")
        Mono<Void> create(@RequestBody Publisher<Person> personStream) {
               returnthis.repository.save(personStream).then();
        }

        @GetMapping("/person")
        Flux<Person> list() {
               returnthis.repository.findAll();
        }

        @GetMapping("/person/{id}")
        Mono<Person> 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<ServerResponse> 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<DataBuffer>。响应与服务器端,json, xml, sse的序列化在WebClient上也都有响应支持。WebClient需要一个ClientHttpConnector实例来诸如特定的HTTP客户端。

下例使用了Reactor Nettty:

WebClient client = WebClient.create(new ReactorClientHttpConnector());

ClientRequest<Void> request = ClientRequest
        .GET("http://example.com/accounts/{id}", 1L)
        .accept(APPLICATION_JSON)
        .build();

原文来自:点融黑帮

声明:所有来源为“聚合数据”的内容信息,未经本网许可,不得转载!如对内容有异议或投诉,请与我们联系。邮箱:marketing@think-land.com

0512-88869195
数 据 驱 动 未 来
Data Drives The Future