Spring Framework 5.0 M5 更新

工程 | Rossen Stoyanchev | 2017年2月23日 | ...

关于 Spring Framework 5.0 第五个也是最后一个里程碑版本的更新……

Spring MVC 和 Spring WebFlux

名称 *Spring MVC* 非常知名且被广泛使用,但可能会让一些人惊讶的是,实际上并没有一个同名项目或独立分发包。它其实是 Spring Framework 分发包中的一个模块,名为 `spring-webmvc`。这是一个额外的知识问题。你知道这个模块中的顶级包并不包含“mvc”吗?它被称为 `org.springframework.web.servlet`。实际上,这些细节我们不必记住。重要的是,我们有一个简短且易于记忆的名称来指代 *Spring 的基于 Servlet 堆栈的* Web 框架。

Spring 的响应式堆栈 Web 框架是 5.0 中的新功能,它是完全响应式和非阻塞的。它适用于使用少量线程的事件循环样式处理。它支持 Servlet 容器(Tomcat、Jetty、Servlet 3.1+),但也支持非 Servlet 运行时(Netty、Undertow),因为此堆栈的通用基础不是 Servlet API,而是基于 Reactive Streams 和 Reactor 项目构建的非阻塞替代方案。如果您想知道,Servlet 3.1 是否能够进行非阻塞 I/O?是的,可以,我们支持在 Servlet 3.1 容器上运行,但其余的 Servlet API 是命令式风格的,不能在响应式、非阻塞堆栈中使用。

到目前为止,我们缺乏对响应式 Web 堆栈的专用名称,该堆栈同时支持 Spring MVC 注解(即 @Controller@RequestMapping)和新的函数式编程模型,这使得讨论和清晰对比编程模型和堆栈成为一项挑战。在我们的里程碑 5 中,spring-web-reactive 模块已重命名为 spring-webflux——从 Spring Web Reactive API 核心中的 Flux 响应式类型 获取灵感和简洁性,我们的低级响应式 HTTP 抽象位于通用的 spring-web 模块中。因此,我们现在并排拥有 spring-webmvcspring-webflux 模块,我们将它们分别称为 *Spring (Web)MVC* 和 *Spring WebFlux*。如果您想知道:新模块中的顶级包是 org.springframework.web.reactive

现在让我们来看一下这个领域的一些其他关键更新……

WebClient

WebClient 是 `RestTemplate` 的一个响应式、非阻塞替代方案,它为 *响应式* 和 *Servlet 堆栈* 应用程序都增加了价值。它使处理异步和流式场景变得轻而易举。

在 M5 中,我们进行了大量改进,消除了指定请求详细信息和执行交换所需的静态导入。

WebClient webClient = WebClient.create();

Mono<Person> person = webClient.get()
        .uri("https://127.0.0.1:8080/persons/42")
        .accept(MediaType.APPLICATION_JSON)
        .exchange()
        .then(response -> response.bodyToMono(Person.class));

如果所有请求都有一个通用的基本 URL,则可以一次性预先配置。

WebClient webClient = WebClient.create("https://127.0.0.1:8080");

Mono<Person> person = webClient.get()
        .uri("/persons/{id}", 42)
        .accept(MediaType.APPLICATION_JSON)
        .exchange()
        .then(response -> response.bodyToMono(Person.class));

也可以使用 UriBuilder 获得编程控制。

Mono<Person> person = webClient.get()
        .uri(builder -> builder.path("/persons/{id}").build("42"))
        .accept(MediaType.APPLICATION_JSON)
        .exchange()
        .then(response -> response.bodyToMono(Person.class));

WebTestClient

`spring-test` 模块中的新 `WebTestClient`构成了 Spring WebFlux 集成测试支持的基础。它包装了一个 `WebClient` 并公开了一个用于集成测试的 API。类似于 Spring MVC Test 中的 `MockMvc`,新的测试客户端不需要实际运行的服务器,可以使用模拟请求和响应直接绑定到 WebFlux 服务器基础结构:````java WebTestClient client = WebTestClient .bindToController(new PersonController()) .build();

client.get().uri("/persons/42") .exchange() .expectStatus().isOk() .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8) .expectBody(Person.class).value().isEqualTo(new Person("John"));


The new test client however can also run against a live server:
````java
WebTestClient client = WebTestClient
        .bindToServer().baseUrl("https://127.0.0.1:8080")
        .build();

// Same test case...

流式处理也很容易测试,可以使用 Reactor StepVerifier

FluxExchangeResult<Person> result = client.get().uri("/persons")
        .accept(TEXT_EVENT_STREAM)
        .exchange()
        .expectStatus().isOk()
        .expectHeader().contentType(TEXT_EVENT_STREAM)
        .expectBody(Person.class)
        .returnResult();

StepVerifier.create(result.getResponseBody())
        .expectNext(new Person("Jane"), new Person("Jason"))
        .expectNextCount(3)
        .consumeNextWith(p -> assertEquals("John", p.getName()))
        .thenCancel()
        .verify();

路径模式解析器

M5 版本添加了一个新的 `PathPatternParser`,它替代了 `AntPathMatcher`,可以使用更有效的请求映射解析模式表示,并支持非常方便的 `"{*foo}"` URI 变量语法来捕获模式末尾的任意数量的段。

第一步,新的 ParsingPathMatcher 实现已经允许将新的 PathPatternParser轻松插入到 Spring MVC 和 Spring WebFlux 映射中。朝着 RC1 的下一步目标是拥有一个模式注册表,以匹配请求路径的解析表示。

服务器发送事件和 JSON 流式处理

使用 Spring WebFlux 很容易支持流式处理:````java @GetMapping(path = "/persons", produces = "text/event-stream") FluxgetPersons() { return this.repository.getPersons(); } ```` 上述代码会将格式化为服务器发送事件 (SSE) 的数据流式传输到浏览器:```` data: {"name":"Jane"} data: {"name":"John"} ... ````

但是,对于以下情况应该怎么做

@GetMapping("/persons")
Flux<Person> getPersons() {
    return this.repository.getPersons();
}

我们可以流式传输单个 JSON 对象,但这不会是一个有效的 JSON 文档,浏览器客户端无法使用除服务器发送事件或 WebSocket 之外的任何方式来使用流。

默认情况下,Flux<Person> 将生成一个 JSON 数组。

[{"name":"Jane"},{"name":"John"},...]

非浏览器客户端(例如 WebClient)可以请求请求内容类型 application/stream+json,响应将是一系列 JSON 对象,类似于服务器发送事件,但没有额外的格式。

{"name":"Jane"}
{"name":"John"}
...

总结

我要感谢所有尝试过 Spring Framework 5.0 并提供反馈的人,尤其是在新的响应式功能方面。请继续这样做。与以往一样,即使是很小的评论也可能非常有价值,因为它们使我们能够从不同的角度重新审视设计选择。

如果您本周是从 DevNexus 阅读本文的,请不要错过 观看令人惊叹的 Josh Long 现场编写响应式 Web 应用程序的机会,也请观看由 Reactor 团队核心成员 Simon Baslé 讲解的 Reactor 3 演讲

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加快您的进步。

了解更多

获取支持

Tanzu Spring在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部