Java 微服務框架新選擇:Spring 5

在這篇文章中,咱們將討論即將發佈的第五代 Spring 框架中的新概念—— 「Functional Web Framework」,來看看它如何幫助咱們構建輕量級的微服務。react

file

你可能會對標題中出現的 「Spring」 和 「微服務框架」感到驚訝。可是確實如此,Spring 5很是適合成爲你 Java Web 微服務框架的新選擇。首先,爲了不混淆讓咱們來對「微服務」中的「微」達成共識:web

簡潔 - 無需樣板工程,無需額外設置spring

簡單 - 沒有任何「魔法」編程

易於部署 - 產生單一的可部署工件json

容易運行 - 沒有額外的依賴segmentfault

輕量級 - 最小內存佔用/CPU 使用服務器

非阻塞 - 更好的併發性網絡

雖然 Spring Boot 已經能作到上述的一些點,但 Spring MVC 自己依然引入了不少魔法。好比 @Controller 這個普遍使用的註解就有點含糊不清,更不用說 Spring 的自動配置和組件掃描等特性了。一般來講,這是開發一個大規模應用時能夠承受的煩惱,畢竟 Spring 幫咱們搞定了依賴注入、請求路由、各種複雜的配置等。然而,在微服務的世界中,應用程序只是相似一個大機器中運行的小齒輪,Spring Boot 就顯得有些「殺雞用牛刀」了。併發

爲了解決這些問題,Spring 團隊引出了一個名爲「Functional Web Framework」的新概念,它是 Spring WebFlux(之前稱爲 Spring Reactive Web)這個大項目的一部分。同時也是咱們如今要討論的。app

首先,讓咱們回顧一下基礎知識,看看一個 Web 應用程序究竟是什麼樣的,以及由什麼組件構成。很顯然,最基本的部分就是網絡服務器(Web server)自己,爲了不手工解析 HTTP 請求,而後委派給應用程序的某個方法,咱們須要一個請求路由器(router),同時咱們也須要一個請求處理器或處理程序(handler),其實就是一段代碼,它能夠接受請求,作實際的邏輯處理,並最終返回一個響應。全部這些也正是 Spring Functional Web 所作的,它剝離了全部的抽象層(beans 和 contexts)。注意,這並不意味着它脫離並放棄了成熟的 Spring MVC 模型,而是提供了使用 Spring 來構建 Web 應用程序的另外一種選擇。

請求處理器

咱們來看一下這個例子。 開始前請訪問 http://start.spring.io 使用項目建立器建立一個新的空白工程,使用 Spring Boot 2.0 和 Reactive Web 做爲惟一的依賴。 接着咱們就能夠定義第一個請求處理器或處理方法(handler)了,很簡單,它接受請求並返回響應。

file

從上述代碼能夠看出來,它是 HandlerFunction 接口的一個實現,定義了一個方法來獲取一個請求(類型爲 ServerRequest),並返回具備 "Hello" 字符串的 ServerResponse 對象。 Spring 還提供了方便的構建器(builder)來構造響應。在咱們的例子中,咱們使用 ok() 自動將返回碼設置爲 HTTP 200 。爲了構造響應體,咱們使用另外一個叫 Mono 的概念,它表明 single reactive value ,但咱們這裏先無論它,只要明白 Mono.just(...) 是一種經過返回 Publisher 類型對象(實際上是相似 Promise)來實現非阻塞編程範式的方式。Reactive Web 是Spring 5 的一部分,它是經過 Java 9 的 Reactive Stream 來實現的。你能夠參考 Dave Syer 的這篇文章。

咱們還可使用 Java 8 的 lambdas 表達式使代碼更簡潔,以下:

file

請求路由器

上面咱們已經有一個 handler 了,如今咱們能夠定義一個請求路由器了。 假設咱們要使用 GET 方法請求 "/" 時調用咱們的 handler。 爲此,咱們可使用 RouterFunction 。

file

route 和 GET 都是 RequestPredicates 和 RouterFunctions 的靜態方法,它們能夠用來構建 RouterFunction 。它接受一個請求,檢查它是否能匹配現有handler(好比請求路徑(path)、請求方法(method)或者是內容類型(content type)等)。若是匹配則調用 handler。 在咱們的例子中,HTTP 方法是 GET,請求路徑是 "/", handler 函數是上面定義的 hello。

file

Web 服務器

如今咱們能夠把他們組裝在一塊兒來完成整個應用程序。咱們將使用很是輕量、簡單的 Reactive Netty 做爲 Web 服務器。要將咱們的請求路由器集成到 Web 服務器中,咱們須要將其轉換爲 HttpHandler。

file

接着這樣來啓動 Web 服務器:

file

其中 ReactorHttpHandlerAdapter 只是一個包裝了 HttpHandler 的 Netty 中的類,其他的代碼很是簡單直白。咱們建立一個新的 Web 服務器,監聽 localhost 地址的8080端口,而且添加咱們的 HTTP handler,實際上這是咱們的請求路由器的入口。

好了!整個應用程序已經差很少了,完整的代碼以下:

file

最後一行只是用來保持 JVM 進程一直運行。 你可能會發現整個應用程序啓動飛快,這是由於沒有任何組件掃描或配置注入發生,就像之前大家使用 Spring 會遇到的。

同時整個程序能夠做爲一個簡單的 Java 應用程序來運行,不須要任何容器。

爲了將整個應用打包和部署,咱們仍然能夠利用 Spring Maven 插件,只需執行如下操做:

file

此命令將生成一個包含全部依賴關係的 fat jar,能夠在僅安裝了 JRE 的環境來部署和執行:

file

另外,若是咱們想查看整個應用的內存使用狀況,大概只有32MB左右,包括了22MB的 metaspace(大家知道用來存放加載的 classes)和大約10MB的 heap。就像前面提到的,整個框架和運行時環境只須要不多的資源。

支持JSON

在上面的示例中,咱們返回一個字符串做爲響應,可是想返回 JSON 對象也很是容易。

讓咱們建立一個新的能夠返回 JSON 的 API endpoint 來擴展咱們的應用。這個 data class 很是簡單,只有一個名爲 name 的字符串類型的字段。爲了不寫那些冗長的 Java 樣板代碼(就像大家厭惡的 setter, getter),咱們使用 Project Lombok 特性:使用 @Data 註解。經過在類上添加此註解,咱們能夠透明得得到 getter,setters,equals 和 hashCode 方法,而無須手動實現。

file

而後,咱們須要擴展咱們的請求路由器,以便爲 "/json" 路徑的 GET 請求提供新的響應。 這能夠經過在現有路由上調用 andRoute(...) 方法來完成。

file

咱們還優化了一點代碼,將新的返回 JSON 的 handler 之內連的方式聲明,同時將 ok() 靜態導入,這使得代碼變得更簡潔。

從新啓動後,應用程序將經過 "/json" 路徑返回 {"name": "world"},同時將響應頭部中的內容類型(content-type)設置爲 application/json。

應用上下文

你可能已經注意到整個代碼中並無定義應用上下文(Application Context)。是的,咱們再也不須要它!Spring WebFlux 中支持 RouterFunction,這樣一個簡單且輕量的 JSON 服務再也不須要應用上下文。

測試

爲了測試 reactive web application,Spring 提供了新的名爲 WebTestClient 的客戶端(相似於 MockMvc)。 咱們將它綁定到咱們的請求路由器上:

file

WebTestClient 有一組針對返回結果的斷言,以驗證返回狀態碼,返回體,以及內容類型等等。

總結

Spring 5 引入了新的編程範式用來開發小型的、輕量級的、微服務式 Web應用程序。 咱們顯式得定義請求路由器和請求處理函數,在徹底不須要應用上下文的狀況下快速運行並部署。

file

本文由博客一文多發平臺 OpenWrite 發佈!
相關文章
相關標籤/搜索