作者: thesixthday, 出處:賽迪網技術社區, 責任編輯: 李春禹,
2007-12-27 13:21 瀏覽器在接收到響應以後,再也不需要進行整個頁面的渲染與重新整理,而只僅僅需要執行這段指令碼內容,將頁面的控制項進行更新即可。更好的方式是,提供一個本身就支援Ajax的Tree組件,以減少冗餘資料的傳遞。
3年前,“Spring之父”Rod.Johnson寫了一本在Java界引起轟動的書:《Expert
One-on-One J2EE Development Without
EJB》。這本書闡述了EJB作為J2EE核心技術所帶來的意義與價值,但作者用了更大篇幅介紹EJB的一些缺陷與不足,並提出了Without
EJB的解決方案。正是由於“J2EE Without EJB”這個激動人心的口號及這本書奠定的基礎,導致了Spring
Framework這個經典輕量級架構的誕生。
2年前,Ajax開始進入人們的視野。時至今日,Ajax已經成為一個紅得發紫的技術。但是今天,我想說一句:JavaEE without Ajax。
Ajax的“原罪”
Ajax為什麼這樣紅?有人說,是因為起了個好聽易記的名字(比如荷蘭著名的Ajax球隊,即阿賈克斯);也有人說,是因為Google全新的
Ajax應用產品給人們帶來的超酷體驗(比如偉大的Google
Maps、GMail等)。確實如此,Ajax能夠如此流行的最主要原因就是它帶來了更好的使用者體驗,改變了人們對傳統Web應用的不佳印象。
然而,即使Ajax的狂熱Fans也不得不承認的是,從技術層面上來說,Ajax並沒有帶來什麼新鮮的東西。它本質上是一種新瓶裝舊酒的技術,
好處是通過Java
Script與DHTML提供了一種非同步編程模型,從而使Web應用給客戶帶來了更好的人機體驗。正如我在去年引起大家爭論的拙文《Ajax,只是一種過
渡技術》中表述的:Ajax解決問題的層面較低。或者說,它解決問題的方法與手段,很難形成一種可高度抽象的架構級解決方案。並且,正是因為Ajax基於
Java Script,因此不可避免地帶來了Java Script的諸多缺點,譬如:
跨瀏覽器是一場噩夢
對搜尋引擎的支援不好
幹掉了Back、History等按鈕(儘管我並不認為Back、History是什麼好東西)
開發與維護成本過高
要Java, 不要Java Script
We Love Java, Not Java Script。套用毛澤東的慣用句式就是:“要Java, 不要Java Script”。相信很多讀者看完這個標題也許會不以為然,但這句話卻代表了許多J2EE開發人員的心聲。
眾多Java工程師都對Java有一種近乎偏執的喜愛,他們熱愛Java的簡潔與優雅。但一旦讓他們去進行Java
Script的開發,卻往往會不知所措:過度靈活的文法,無法通過編譯器進行文法校正,缺乏良好的調試工具等等這些,都會讓人們對Java
Script畏手畏腳,更遑論Ajax的開發。
一句話,Java社區需要Ajax,需要它來提升基於JavaEE的Web應用的人機體驗;但是,人們並不喜歡Ajax目前的開發模式。無疑,我們需要一種新的解決方案。
誰來拯救JavaEE的Ajax?
我給出的答案是JSF。目前,關於JSF的一種流行說法是“悲劇人生:Sun讓JSF光著身子降臨到Java Web世界”。然而,我的看法卻是:作為一種革命性的伺服器端組件技術,JSF猶如早晨八九點鐘的太陽,前途不可限量。
讓事實說話,我們先來看看JSF請求/響應過程的標準生命週期:
圖1:JSF的生命週期
通過可以觀察到,任何一個JSF“Faces Request” 請求,經過Restore View、Apply Request
Values、Process Validations、Update Models、Invoke Application等階段以後,產生了一個
“Render Response” 返回給用戶端。那麼,常規JSF引擎是如何?上述過程的呢?
瀏覽器在接收到響應以後,再也不需要進行整個頁面的渲染與重新整理,而只僅僅需要執行這段指令碼內容,將頁面的控制項進行更新即可。更好的方式是,提供一個本身就支援Ajax的Tree組件,以減少冗餘資料的傳遞。
圖2:常規JSF引擎的請求與響應過程
回顧一下常規JSF引擎針對請求與響應的過程:首先,用戶端請求某個資源,產生一個Faces
Request;伺服器端接收到此請求以後,經過一系列幕後處理,產生一個Faces
Response。我們注意到:響應的Content-Type是text/html,而產生的內容主體是一段HTML文本;瀏覽器在接收到HTML文本
以後,進行整個頁面的渲染與重新整理。
無需寫Ajax代碼的Ajax Enabled應用
我用自己開發的JSF引擎,這樣處理上述過程(詳見參考資料www.OperaMasks.org ),如所示:
圖3:OperaMasks JSF實現的請求與響應過程
首先可以觀察到,Faces Request的發出是基於“x-requested-by: XML Http
Request”,也就是說,這是一個Ajax請求,而該請求在到達伺服器端以後,伺服器端所產生的Faces Response同常規Faces
Response相比也發生了變化:Content-Type不再是text/html,變成了text/javascript;並且,響應的主體也不再
是html文本,而是一堆script指令碼。瀏覽器在接收到響應以後,再也不需要進行整個頁面的渲染與重新整理,而只僅僅需要執行這段指令碼內容,將頁面的控制項
進行更新即可。
顯而易見,通過上述JSF技術,我們獲得了:
基於Ajax的請求、應答、及頁面控制項的更新
資料轉送量明顯減少
避免整個頁面的重新整理,更好的使用者體驗
系統保持敏捷、高效
換言之:任何標準JSF應用,只需將其在OperaMasks JSF引擎上運行,就可以達到這樣的效果。我們並沒有寫任何一行Ajax的代碼,但是,我們的應用卻是自然而然的Ajax Enabled的應用。大道至簡,大象無形。
奧妙所在:JSF的Render機制
為什麼可以這樣?
JSF組件只是特定狀態和行為的載體,而組件以什麼形式去和使用者互動,是完全可定製的、獨立於該特定的表現語言,可以是HTML、WML或者其
他形式;具體是什麼,可以通過指定JSF組件的Render Kit來實現,而每一種Render
Kit,對應於組件作者寫的同一風格和形式的一系列Render。
比如,如果想在網頁中實現圖表功能(Chart),MSIE有VML,Gecko和Opera有SVG;而在伺服器端只需要簡單地判斷一下瀏覽器類型,就可以選擇一個Render Kit,產生不同的用戶端表現來完成相同功能――這是用常規JSP技術很難完成的任務。
通俗的說,JSF組件可以翻譯成任何你想要的形式。So,JSF架構比現有其它開源架構具有更強的生命力。上文所述的OperaMasks JSF,其容器層級Ajax實現,正是靈活應用Render Kit的具體案例。
從容器層級對Ajax予以支援的JSF引擎
我們提出的JSF是直接由JSF容器來處理Ajax請求的,它會根據請求類型來判斷這是一個正常HTTP請求還是一個
Ajax請求:如果是常規HTTP請求就運行JSP頁面,產生頁面文檔(特定的,對於Ajax Render
kit,要加入一些Ajax基礎JavaScript代碼);如果是Ajax請求,伺服器對請求參數正常解碼,並執行JSF中除頁面輸出階段以外的所有其
他階段,產生一個JSF組件樹。
一直到這一步為止,處理方式與對普通HTTP請求的處理完全一致,唯一不同的是:在隨後Render
Response階段,容器除了調用組件作者寫的Ajax功能
Renderer以外,更重要的是在產生響應頁面時,會過濾掉一切不會變化的靜態內容――也就是說,靜態內容不會產生到響應頁面中去,而對每一個動態內容
則會產生一個相應JavaScript代碼(可以更進一步最佳化為只有變化了的動態內容才處理)。這樣,傳給客戶的Ajax應答實際上是由這樣一些
JavaScript語句構成。在Ajax響應返回到用戶端時,就可以自動由Ajax回呼函數執行這些JavaScript語句,完成對頁面即時的、局部
的更改,而不需要重新整理整個頁面。依賴JSF組件的具體功能,甚至可以改變頁面的外觀。而整個Ajax機制由JSF引擎提供,對使用者完全透明。
實際上,在JSF規範中JSF頁面輸出階段所採用的Render Kit是可替換的,預設的HTML_BASIC Render
Kit輸出的是標準HTML文法,不包含任何Java Script代碼。我們提出的JSF引擎實現了一個 Ajax Render
Kit,可以在HTML文檔中嵌入Java Script代碼來實現Ajax特性,而替換Render Kit只需要修改設定檔即可。
簡單地說,這種JSF引擎為每個標準組件都實現了相應的Ajax Render, 比如對UICommand組件,其Ajax
Render會在onclick事件中加入JavaScript的Ajax提交代碼,向伺服器提交Ajax請求。通過這種方式,任何一個包含標準JSF組
件的Web應用,都可以通過只更改Render Kit配置為Ajax來實現Web應用Ajax化。而對於第三方的組件,可能本身並不支援
Ajax,但使用一個名為的標籤,就可以立即將這個第三方組件轉換成Ajax Enabled。
例如,Apache
myfaces的Tomahawk項目提供了一個Tree組件,這個組件本身並不支援Ajax,每當按下一個Tree結點都將重新重新整理整個頁面。使用標籤
後,則只重新整理Tree部分,而不重新整理頁面的其他部分。當然更好的方式是,提供一個本身就支援Ajax的Tree組件,以減少冗餘資料的傳遞。關於標籤的原
理,有興趣的讀者可以參考OperaMasks JSF的源碼(詳見參考資料),這裡就不再一一贅述了。
綜上,JavaEE 需要Ajax,但並不需要傳統的Ajax開發模式。通過我們提出的OperaMasks JSF技術,我們不再需要知道什麼是Ajax,而我們的應用卻是自然而然的Ajax Enabled應用。
因此,我們認為:JavaEE Without Ajax!