JSF的加減法
JSF 本身是很多問題的。當然,JSF不是一項技術,而是標准。看看 Javax.faces.* 包裡的內容,不是抽象類就是接口,是沒有實現的。 JSF 出來的時候目的也不是面向應用開發者的,而是面向組件供應商的,從這點意義上來說,JSF是成功的。Sun提供了一個reference implementation, 但是那更像是教組件供應商如何做組件的一個demo,而非真正意義上的給應用開發人員用的成型的組件。
標准因為要融合各方需求,所以內容只能是各方能力的交集。至於標准之外的東西,則需要各方去發揮。
JSF標准因為是先於成型的應用出來的(不同於EJB3的借鑒hibernate和spring,JSF299的借鑒seam),難免會有預見不足的地方。在某些地方可能作了過分的限制,而另外某些地方則完全沒有規定放得太開導致標准實現商完全忽略了它們。
但是 JSF 的初衷是不錯的,而且標准本身也足夠的可擴展。 所以現在才會誕生如此多的基於 JSF 的框架。 這些框架在不同程度上修復了 JSF 初始制定時的不足。
AJax4JSF, Facelets, Seam 是這其中三個獨立的方向。
1. A4J: 用網絡檢測工具可以清晰地看到,每次在JSF postback 的時候,雖然可能只有部分頁面需要刷新,但整個頁面都會被從服務器送往浏覽器。這是非常浪費的。 JSF的event-driven模型實際上非常適合部分頁面刷新(試想如果沒有事件模型,每晃一下鼠標顯示器就把整屏幕重畫,現在也就沒有 Windows了),但是因為ajax出來的時候JSF標准已經final了,就沒有把Ajax考慮進去。對於事件模型來說,把整屏幕重畫改為部分組件重畫是件相對容易的事情,這也就是 Ajax4JSF 這個項目的目的。是否開啟AJax,可以不需要Javascript,只是更改頁面中的某個開關(tag)就行了。
2. Facelets: JSF是建立在JSP上的,但這是完全沒有必要的。JSP不是模板語言,它只是簡單得把嵌入在html裡的java語言原樣放入Java的源文件裡,實際上是混合的Html和Java。這種模型和JSF的事件模型沒有任何互補的關系。相反,它給JSF加入了不必要的限制。Facelets的目的在於取代 JSP在JSF裡的地位。它是真正的模板語言,el表達式可以嵌入在頁面的任何位置,比如寫成:
<h2>Hi,I'm Jordan, I think the winner of this cup is #{winner.name}, is that right?</h2>
Facelets不需要編譯,頁面是hot-deploy的,性能比JSP快。另外,facelets本身提供了加參模板的功能,定制新的組件可以完全不寫Java,只把頁面裡的需要提成組件的內容扔進分離的頁面,並且在taglib.XML裡面加入tag指向分離的頁面,並指定參數名字就可以了。 JSF最為人诟病的組件缺乏的問題,在facelets這裡得到了緩解,實際上是不怎麼需要第三方組件就可以快速寫出舒服的代碼來。Facelets還有其它的功能,比如debug頁面顯示facelets頁面出錯的行號,比如無限嵌套的模板,等等。
3. Seam: Seam 其實本身是無關JSF的,但是因為它從一開始就建在JSF上面,所以也不得不對JSF的一些問題進行修復。
Seam的工作需要分開來細說:
◆page行為
◆Context-filter
◆RESTful(重建頁面參數)
◆異常處理
◆跨越重定向的狀態
現在我們有了JSF的加減法:
JSF - (全頁面刷新) + AJax4JSF - JSP + Facelets + 全局Page行為 + Context-filter + Restful參數綁定 + 可定制異常 + 跨越重定向的狀態 = “ -_- !一大碗炸醬面”
就好像一件黃金聖衣,經過無數次修補,雖然還能再用,但是實在不如重鑄了。
JSF 需要一套整合的模型,使這些各個分散的部分重新以一種整體的局面展現出來。它需要把多余的東西拋棄掉,把新的內容以更集成的方式融在一起,因為光是熟悉這些不同分散的部分,理解它們之間的關系,知道哪裡會有BUG,哪裡則可以避免這些BUG,並且在運用的時候總是用對該用的東西,這已經使人非常頭大了。 JSF作為標准來說是成功的,在這一標准下有了如此多的可以插拔的第三方軟件。但是該是時候對這些零散的東西統一了。就好像ubuntu在統一的指導思想下集合了盡可能多的零散的開源軟件,使它們可以被一種簡單並且相似的方式獲取,使我不需要像在Gentoo裡安裝任何一個東西都要搜索搜索再搜索,了解它的來源,了解它的BUG,了解我的硬件是否支持。作為用戶,我不想學習,我想有明白的人替我作決定,那是最好的,特別是當這些決定make sense的時候。
現在的Seam正是朝這個方向走的。能走這樣的路,得有兩個條件,一是有眾多零散的可用的東西,但是它們缺乏統一的形式(但它們得有能夠統一的背景,比如 ubuntu下是posix標准,Seam下是JSF標准);二是有對該領域非常熟悉的人來做這樣的事情。上面提到的Seam對JSF的改進其實只是 Seam框架下非常小的一部分,是Seam在向這個目標前進的必須的一個步驟,是在Seam內核基礎上水到渠成的東西,而遠非Seam的全部。正如 Seam的名字所示:縫合;正如ubuntu的名字所示:分享與同在。它們的制定者在決定之初即是向著這一目標前進的。
已經early draft revIEw的JSR 299, 即是借鑒了Seam(以及其它比如Guice)的一個標准,試圖把這一方向推得更遠。
至於對於縫合所需要的本事,Seam的conversation模型,CoC理念,元注解配置+XML補充方式,動態雙向注入模型(不同於spring的靜態單向注入),擴展了的EL等,是其基礎。內部事件和監聽模型,和drools的安全集成模型,和hibernate-seach, hibernate-validation, seam-remoting, jbpm,groovy,itext的集成,是其在基礎之上的應用。這些則需要另外的文章來寫了。
不說Seam誕生的大環境和Seam產生的語言基礎,只是說Seam本身的功能,大概也可以,不過我認為非常多的外在功能都只是某些環境外在因素和基本內在因素所決定了的。大環境和內在可能定了之後,細節的東西只是做就可以了。所以沒有辦法,還是得繞開Seam本身說些題外話。
JSF的加減法說了一下 Seam誕生的環境,這是外在機會,是融合各種技術的可能性,是廣的緯度。 這篇文章說說Java上的可能性,是何讓Seam具有了融合的本事,是內在能力,從深的緯度上說吧。