對Java開發者來說,2017年9月是個熱鬧的月份,非但Java SE 9、Java EE 8相繼釋出,就連Spring框架,也在這段時間發布5.0正式版。

而新版Spring的一大特色,就是Reactive Web方案Web Flux,這是用來替代Spring Web MVC的嗎?或者,只是終於可以不再基於Servlet容器了?

基於Servlet容器的Web MVC

身為Java開發者,對於Spring框架並不陌生。它最初起源於2002年、Rod Johnson著作《Expert One-on-One J2EE Design and Development》中的Interface 21框架,到了2004年,推出Spring 1.0,從XML到3.0之後,支援JavaConfig設定;進一步地,在2014年時,除了Spring 4.0之外,首次發表了Spring Boot,最大的亮點是採用自動組態,令基於Spring的快速開發成為可能。

對Web開發者來說,Spring中的Web MVC框架,也一直隨著Spring而成長,然而由於基於Servlet容器,早期被批評測試不易(例如:控制器中包含了Servlet API)。

不過,從實作Controller介面搭配XML設定,到後來的標註搭配JavaConfig,Web MVC使用越來越便利。如果願意,也可採用漸進的方式,將基於Servlet API的Web應用程式,逐步重構為幾乎沒有Servlet API的存在(可參考先前專欄文章〈篩選框架必要功能〉),在程式碼層面達到屏壁Servlet API的效果。

由於不少Java開發者的Web開發經驗,都是從Servlet容器中累積起來的,在這個時候,Web MVC框架基於Servlet API,就會是一項優點。因為,雖然運用Web MVC撰寫程式時,可做到不直接面對Servlet API,然而,也意味著更強烈地受到Spring的約束,有時則是無法在龐雜設定或API中找到對應方案,有時也因為心智模型還是掛在Servlet容器,經驗上難以脫離,在搞不出HttpSession、ServletContext對應功能時,直接從HttpSession、ServletContext下手,畢竟也是個方法。

撰寫程式時,就算沒用到Servlet API,Web MVC基於Servlet容器仍是事實,因為,底層還是得借助Servlet容器的功能,例如Spring Security,本質上還是基於Servlet容器的Filter方案。

然而在今日,Servlet被許多開發者視為陳舊、過時技術的象徵,或許是因為這樣,在Java EE 8宣布推出的這段期間,當我在某些場合談及Servlet 4.0之時,總會聽到有人提出「Web Flux可以脫離Servlet了」之類的善心建議。

實現Reactive Streams的Reactor

Web Flux不依賴Servlet容器是事實,然而,在談及Web Flux之前,我們必須先知道Reactor專案,它是由Pivotal公司,也就是目前Spring的擁有者推出,實現了Reactive Streams規範,用來支援Reactive Programming的實作品。

既然是實現了Reactive Streams規範,開發者必然會想到的是RxJava/RxJava 2,或甚至是Java 9的Flow API。這也意謂著,在能使用Web Flux之前,開發者必須對於Reactive Programming典範,有所認識,如果你從未接觸過這些玩意兒,可以參考先前專欄〈Reactive 與 Java 9〉。

開發者這時有疑問了,Spring為何不直接基於RxJava 2,而是打造專屬的Reactive Streams實作呢?

就技術而言,Reactor是在Java 8的基礎上開發,並全面擁抱Java 8之後的新API,像是Lambda相關介面、新日期與時間API等,這意謂著,專案如果還是基於Java 7或更早版本,就無法使用Reactor。

在API層面,RxJava 2有著因為歷史發展脈絡的原因,不得不保留一些令人容易困惑或混淆的型態或操作,而Reactor在這方面,都有著明確的對應API來取代,然而,卻也提供與RxJava 2(甚至是Flow API)間的轉換。

另一方面,Reactor較直覺易用,例如最常介紹的Mono與Flux,實現了Reactive Streams的Publisher介面,並簡化了訊息發布,讓開發者在許多場合,不用處理Subscriber和Subscription的細節(當然,這些在Reactor也予以實現)。而在Spring Web Flux中,Mono與Flux也是主要的操作對象。想知道如何使用Mono與Flux,可以參考〈使用Reactor進行反應式編程〉(https://goo.gl/vc2fGc)。

又一個Web框架?

到了Spring 5,在Reactor的基礎上,新增了Web Flux作為Reactive Web方案,我們在許多介紹文件的簡單範例,例如〈使用Spring 5的WebFlux開發反應式Web應用〉(https://goo.gl/G5uotZ),就看到當中使用了Flux、Mono來示範,而且,程式碼看起來就像是Spring MVC。

這是因為Web Flux提供了基於Java標註的方式,有許多Web MVC中使用的標註,也拿來用在Web Flux之中,讓熟悉Web MVC的開發者也容易理解與上手Web Flux,然而,這不過就是新的Web框架嗎?

實際上,當然不是如此。Web Flux並不依賴Web MVC,而且它是基於Reactor,本質屬於非同步、非阻斷、Reactive Programming的心智模型,也因此,如果打算將Web Flux運行在Servlet容器之上,必須是支援Servlet 3.1以上,因為才有非阻斷輸入輸出的支援,雖然Web Flux的API在某些地方,確實提供了阻斷的選項,若單純只是試著將基於Web MVC的應用程式,改寫為套用Web Flux,並不會有任何益處,反而會窮於應付如何在Web Flux實現對應的方案。

例如,此時,Spring Security顯然就不能用了,畢竟是Spring基於Servlet的安全方案,開發者必須想辦法套用Spring Security Reactive;而且,在儲存方案上,也不是直接採用Spring Data,而是Spring Data Reactive等。

就算能套用相關的設定與API,要能獲得Web Flux的益處,應用程式中相關的元件,也必須全面檢視,重新設計為非阻斷、基於Reactive Programming方式,這或許才是最困難、麻煩的部份。

除了基於Java標註的方式,讓熟悉Web MVC的開發者容易理解之外,Web Flux還提供了基於函數式的設計與組態方式。

實際上,在運用RxJava 2/Reactor等Reactive Streams的實作時,我們也都必須熟悉函數式的思考方式,才能充分掌握,這點在Web Flux並不例外。

可以脫離Servlet容器了?

Servlet容器是個舊時代的象徵,如果能夠屏蔽Servlet容器或相關API,許多開發者應該都會很開心,可以少一層抽象,不必使用肥肥的Servlet容器,當然會是使用Web Flux時附帶的優點,然而,如果只是為了屏蔽Servlet,其實,早就有其他技術選擇存在。

基於Servlet一路發展過來的Web MVC,雖然目前在某些地方可以安插一些函數式的設計,然而,本質上不變的部分在於,在技術堆疊中所隱含的,仍是一個基於同步、阻斷式、命令式的心智模型。如果在這樣的堆疊中,開發者老是因為想要實現非同步、非阻斷、Reactive、函數式而感到不快,Web Flux也許才會是可考慮的方案,而不單只是用來作為脫離Servlet容器,Web MVC的替代品。

整體而言,Web Flux還算是新技術,也還有待時間驗證可行性,如果只是為了想用Web Flux來取代Web MVC,或甚至更小一點的野心,只是想要能脫離Servlet容器,最好在採取行動之前,全面檢視一下,確認自身或團隊成員是否準備好接受Web Flux的心智模型,或者真的存在著對應的應用場景吧!

專欄作者

熱門新聞

Advertisement