就現代程式開發而言,只要談到框架,多半令人感到沉重,這主要是來自兩個方面:其一是應用程式到了一定規模,須基於某套半成品,才能加速開發;其二則是半成品本身,為了應付各式需求,本身往往也龐大到令人窒息。

更糟糕的是,開發者要接觸的半成品,經常不會只有一種,想要樣樣精通基本上是不可能的!

可以帶一下Spring MVC嗎?

在Java全盛時期,開放原始碼專案百花齊放的那個年代,有著各式各樣的框架,而且各自發展迅速,版本變更快到開發者不得不停下腳步,思考追逐新框架或新版本的意義究竟何在?

仔細想想,有些新功能用來省事,其實只是換了個新封裝,卻重複著舊的模式;有的功能則是基於新觀念,有待社群進一步地驗證可行性。無論是哪個,似乎都不能作為繼續亦步亦趨的理由。

在工作也暫時用不上的情況下,被我暫時放生的框架之一是Spring,在Spring 2.0 之後就不常接觸。過了多年,現在5.0都出了,雖然大致知道主打的特點是什麼,但並未去玩弄過細節。直到不久前,一門Servlet/JSP教育訓練接近尾聲時,有學員閒聊時談到:「可以帶一下Spring MVC嗎?很多同事接下來必須使用,只是東西超多,不知從何下手!」

我內心的OS是:「呃!都接近課程尾聲了,還能怎樣?」對於這類需求,通常會被我婉轉拒絕,而且,都這麼多年沒碰Spring MVC了啊!然而,腦袋中迅速地閃過了幾個畫面,嘴角一滑,就開口說道:「好啊!我抽一、兩個小時帶一下,至於原本課程後面的OOXX,自己看書也可以!」

這突如其來的勇氣,倒也不是信口開河,雖然是Servlet/JSP教育訓練,然而,使用了一個MVC架構的Web應用程式,貫穿整個課程,在適當階段也都運用重構,切分出Facade、DAO等各式元件,正好Web層可以套用Spring MVC,而中間層的元件可以用Spring DI來解決。

然而,兩個小時左右的時間畢竟有限,必須篩選框架的功能,只講解必要的部份。為了銜接課程,我還是先在web.xml中設定DispatcherServlet,然後,其餘部份儘量採零配置(zero configuration),幸而早就以Servlet/JSP自幹出MVC架構的範例,因此,對於零配置時採用的慣例(Convention)配置是什麼,學員並不難理解。

熟悉框架底層

因為,Spring MVC有一點不錯的設計,那就是控制器的方法,可以直接注入Servlet API,像是HttpServletRequest、HttpServletResponse。這意味著:直接複製原Servlet中的程式碼,放到Spring控制器中,重新命名方法、下幾個標註、自動注入Facade元件,控制器就可以動起來了。

至於HttpServletRequest、HttpServletResponse做什麼用的?在接下來的課程,當然就不必再解釋,後續只要檢視程式碼,如果方法中實際上只用到HttpSession,就只要刪掉HttpServletRequest、HttpServletResponse,改注入HttpSession即可。類似地,若只用到HttpServletRequest,此時,我們就只需要注入HttpServletRequest;若只用到HttpServletResponse,就只需注入HttpServletResponse。

實際上,如果方法中只需要請求參數呢?方法參數的部份,就改標註@RequestParam;如果最後只是轉發(forward),那就return一個字串,而請求參數的注入、轉發API什麼的細節,就可以帶入前端控制器模式(Front controller)的概念了,並可以一併解釋Spring DI容器、自動掃描標準、自動綁定的概念,是如何由DispatcherServlet開始這一切的。

這就是為何開發者常說的「要知道框架底層原理」。Spring MVC是基於Servlet,若熟悉Servlet API,在有個Servlet/JSP建構的Web應用程式,而且已經符合MVC架構,基於Servlet API篩選出Spring MVC中最基本元素,去掉不必要的配置,才能馬上感受到框架的好處。

基於框架的持續重構

嗯?這樣就算使用Spring MVC嗎?為什麼不算?如果打從一開始,只在控制器的方法中,注入HttpServletRequest、HttpServletResponse,就算還沒用Spring DI來組合Facade、DAO等元件,此時,只要應用程式能如常運作,就是使用Spring MVC,沒有人規定須用到什麼程度、用了哪些API,才算是使用了一個框架!

當然,有人會說,這太浪費框架的功能了,是沒錯!只是,框架的功能是否有價值,在於它能不能為你的應用程式帶來益處。

例如,使用@Autowired自動綁定Facade元件,能使應用程式省去自行組合依賴關係的麻煩,又能使程式架構清楚;而使用@RequestParam,一眼就知道該變數代表請求參數;若使用@PathVariable,我們馬上就知道是路徑變數,那就不用特別注入HttpServletRequest。因而,值得基於這些功能來重構應用程式。

所以,這也可以用來判定一個框架,是否適合你的方式。框架應該要有個最小集合,而這個最小集合,最好可以基於開發者既有的技術背景,在略為重構(原型)應用程式,以使用此最小集合後,就能使應用程式運行起來,之後隨著對框架認識的越多,在判定框架中的特定功能是否適用,之後,再逐步重構應用程式能使用該功能。

就像Spring MVC呈現技術不一定要用JSP,那麼,該使用其他模版技術嗎?這就要問你自己了,對於JSP有什麼不滿嗎?對於想使用的模版技術,又認識得夠多嗎?它又能解決你在JSP中遇到的什麼問題?這些答案,也決定要不要重構新的模版功能。

也就是說,沒必要全面瞭解一個框架,再來使用框架,也沒必要使用框架的全部功能。認識多少、就用多少,其餘暫且基於既有熟悉的技術也無妨。

在一知半解的情況下,勉強使用某些框架功能,反而是危險的。也許是忽略了生命週期,而造成除錯困難;或者是忽略了技術細節,而造成效能低弱,更糟的情況,可能因為不知道各元件環節之間如何銜接,而造成了安全漏洞。

為了避免一知半解,在調查功能細節的過程,必須採取系統性的作法,單靠網路上的零散文件,只會造成困擾,改為透過一本專書是不錯的選擇。

因為,若框架有些歷史了,一本專書往往會交代一些各版本的變異,以及最佳實踐的變化,甚至是中心思想或者既有典範的轉移等,而這些在決定框架功能的用與不用之時,會是個參考基準。

篩選必要功能的方式

許多開發者都認為,框架可以視為程式語言的延伸,只不過,若生態系很活躍,而框架本身也蓬勃發展的話,這套語言的延伸,很容易擴展到像是沒有邊界的狀態,而對於這類框架,想要全面掌握是沒有意義也不可能的,因而必須要有方式來篩選必要功能。

所以,掌握一門框架的中心思想是個出發點。因為,理解底層或者實作方式,可以大致構築出框架各個功能的運作原理。舉例來說,如果有個原型應用程式,我們可以試著找出框架的最小集合,重構應用程式來套用那個最小集合;接著,系統性地吸收框架知識,找出令原型應用程式能獲得益處的功能,逐步重構應用程式來套用那些功能。

最重要的是謹記,別試圖用上全部的功能,也不用試著追逐每個新增的功能,而是懂得如何篩選出對應用程式本身來說的必要功能,如此就算框架是龐大的,對你來說也會是簡潔的!

專欄作者

熱門新聞

Advertisement