Spring Framework 5.0 M5 更新

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

Spring Framework 5.0 第 5 個也是最後一個里程碑版本的更新...

Spring MVC 和 Spring WebFlux

“Spring MVC”這個名字非常熟悉且被廣泛使用,但也許會讓一些人驚訝的是,實際上並沒有一個名為“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-webmvc` 和 `spring-webflux` 這兩個模組並排存在,我們將分別稱它們為Spring (Web) MVCSpring WebFlux。如果您想知道:新模組的頂級包是 `org.springframework.web.reactive`。

接下來是一些在這個領域裡的其他重要更新...

WebClient

`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));

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://: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 的下一步,目標是建立一個模式登錄檔,以便與請求路徑的解析表示進行匹配。

Server-Sent Events 和 JSON 流式處理

使用 Spring WebFlux 進行流式處理非常容易:`` `java @GetMapping(path = "/persons", produces = "text/event-stream") FluxgetPersons() { return this.repository.getPersons(); } ```` 上述程式碼將資料以 Server-Sent Events (SSE) 的格式流式傳輸到瀏覽器:`` `data: {"name":"Jane"} data: {"name":"John"} ... ````

但是,應該怎麼處理

@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 講座

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有