搶佔先機
VMware 提供培訓和認證,助您飛速進步。
瞭解更多關於 Spring Framework 5.0 第五個也是最後一個里程碑的更新...
`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 的其餘部分是命令式風格的,不能在反應式、非阻塞的棧中使用。
迄今為止,我們一直缺乏一個專門的名稱來指代既支援 Spring MVC 註解(即 @Controller
, @RequestMapping
)又支援新函數語言程式設計模型的反應式 Web 棧,這使得討論和清晰對比各種程式設計模型和棧變得具有挑戰性。在我們的里程碑 5 中,spring-web-reactive
模組被重新命名為 spring-webflux
——靈感和簡潔性來自於 Spring Web Reactive API 核心的 Flux 反應式型別,而我們較低級別的反應式 HTTP 抽象則位於通用的 spring-web
模組中。因此,我們現在有了並存的 spring-webmvc
和 spring-webflux
模組,我們將分別稱之為 *Spring (Web)MVC* 和 *Spring WebFlux*。如果你想知道,新模組的頂層包是 org.springframework.web.reactive
。
接下來是這個領域的一些其他重要更新...
`WebClient` 是 `RestTemplate` 的反應式、非阻塞替代方案,為*反應式*和*Servlet 棧*應用都帶來了價值。它使得處理非同步和流式場景變得輕而易舉。
在 M5 中,我們進行了重大改進,消除了指定請求詳情和執行交換時對靜態匯入的需要
WebClient webClient = WebClient.create();
Mono<Person> person = webClient.get()
.uri("https://:8080/persons/42")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.then(response -> response.bodyToMono(Person.class));
如果所有請求都有一個共同的基礎 URL,可以一次性預配置
WebClient webClient = WebClient.create("https://: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));
`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://: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 的下一步目標是建立一個模式登錄檔,用於與請求路徑的已解析表示進行匹配。
使用 Spring WebFlux 可以輕鬆支援流式傳輸:````java @GetMapping(path = "/persons", produces = "text/event-stream") Flux
但是對於
@GetMapping("/persons")
Flux<Person> getPersons() {
return this.repository.getPersons();
}
我們可以流式傳輸單個 JSON 物件,但這作為一個整體將不是一個有效的 JSON 文件,並且瀏覽器客戶端除了使用 Server-Sent Events 或 WebSocket 之外沒有其他方式來消費流。
預設情況下,Flux<Person>
將生成一個 JSON 陣列
[{"name":"Jane"},{"name":"John"},...]
非瀏覽器客戶端(例如 WebClient
)可以請求內容型別為 application/stream+json
,響應將是一個 JSON 物件流,類似於 Server-Sent Events 但沒有額外的格式。
{"name":"Jane"}
{"name":"John"}
...
我要感謝所有嘗試過 Spring Framework 5.0 並提供反饋的人,尤其是關於新的反應式特性。請大家繼續這樣做。一如既往,即使是小的評論也可能非常有價值,因為它們讓我們從不同的角度重新審視設計選擇。
如果你本週在 DevNexus 閱讀這篇文章,不要錯過機會觀看 了不起的 Josh Long 現場編碼一個反應式 Web 應用,也不要錯過 Reactor 團隊核心成員 Simon Baslé 關於 Reactor 3 的演講。