終於正式進入J2ee的細節部分了,首當其沖的當然是Servlet和Jsp了,上篇曾經提到過J2ee只是一個規范和指南,定義了一組必須要遵循的接口,核心概念是組件和容器。曾經有的人問筆者Servlet的Class文件是哪裡來的?他認為是J2ee官方提供的,我舉了一個簡單的反例:稍微檢查了一下Tomcat5.0裡面的Servlet.jar文件和JBoss裡面的Servlet.jar文件大小,很明顯是不一樣的,至少已經說明了它們不是源自同根的吧。其實Servlet是由容器根據J2ee的接口定義自己來實現的,實現的方式當然可以不同,只要都遵守J2ee規范和指南。
上述只是一個常見的誤區罷了,告訴我們要編譯運行Servlet,是要依賴於實現它的容器的,不然連jar文件都沒有,編譯都無法進行。那麼Jsp呢? Java Server Page的簡稱,是為了開發動態網頁而誕生的技術,其本質也是Jsp,在編寫完畢之後會在容器啟動時經過編譯成對應的Servlet.只是我們利用Jsp 的很多新特性,可以更加專注於前後台的分離,早期Jsp做前台是滿流行的,畢竟裡面支持Html代碼,這讓前台美工人員可以更有效率的去完成自己的工作。然後Jsp將請求轉發到後台的Servlet,由Servlet處理業務邏輯,再轉發回另外一個Jsp在前台顯示出來。這似乎已經成為一種常用的模式,最初筆者學習J2ee的時候,大量時間也在編寫這樣的代碼。
盡管現在做前台的技術越來越多,例如Flash、Ajax等,已經有很多人不再認為Jsp重要了。筆者覺得Jsp帶來的不僅僅是前後端分離的設計理念,它的另外一項技術成就了我們今天用的很多框架,那就是Tag標簽技術。所以與其說是在學習Jsp,不如更清醒的告訴自己在不斷的理解Tag標簽的意義和本質。
1.Servlet以及Jsp的生命周期
Servlet是Jsp的實質,盡管容器對它們的處理有所區別。Servlet有init()方法初始化,service()方法進行Web服務,destroy()方法進行銷毀,從生到滅都由容器來掌握,所以這些方法除非你想自己來實現Servlet,否則是很少會接觸到的。正是由於很少接觸,才容易被廣大初學者所忽略,希望大家至少記住Servlet生命周期方法都是回調方法。回調這個概念簡單來說就是把自己注入另外一個類中,由它來調用你的方法,所謂的另外一個類就是Web容器,它只認識接口和接口的方法,注入進來的是怎樣的對象不管,它只會根據所需調用這個對象在接口定義存在的那些方法。由容器來調用的Servlet對象的初始化、服務和銷毀方法,所以叫做回調。這個概念對學習其他J2ee技術相當關鍵!
那麼Jsp呢?本事上是Servlet,還是有些區別的,它的生命周期是這樣的:
a)一個客戶端的Request到達服務器 ->
b)判斷是否第一次調用 -> 是的話編譯Jsp成Servlet
c)否的話再判斷此Jsp是否有改變 -> 是的話也重新編譯Jsp成Servlet
d)已經編譯最近版本的Servlet裝載所需的其他Class e)發布Servlet,即調用它的Service()方法
所以Jsp號稱的是第一次Load緩慢,以後都會很快的運行。從它的生命的周期確實不難看出來這個特點,客戶端的操作很少會改變Jsp的源碼,所以它不需要編譯第二次就一直可以為客戶端提供服務。這裡稍微解釋一下Http的無狀態性,因為發現很多人誤解,Http的無狀態性是指每次一張頁面顯示出來了,與服務器的連接其實就已經斷開了,當再次有提交動作的時候,才會再次與服務器進行連接請求提供服務。當然還有現在比較流行的是Ajax與服務器異步通過 xml交互的技術,在做前台的領域潛力巨大,筆者不是Ajax的高手,這裡無法為大家解釋。2.Tag標簽的本質
筆者之前說了,Jsp本身初衷是使得Web應用前後台的開發可以脫離耦合分開有效的進行,可惜這個理念的貢獻反倒不如它帶來的Tag技術對J2ee的貢獻要大。也許已經有很多人開始使用Tag技術了卻並不了解它。所以才建議大家在學習J2ee開始的時候一定要認真學習Jsp,其實最重要的就是明白標簽的本質。
Html標簽我們都很熟悉了,有<html> 、<head> 、<body> 、<title> ,Jsp帶來的Tag標簽遵循同樣的格式,或者說更嚴格的Xml格式規范,例如<jsp:include> 、 <jsp:useBean> 、<c:if>、<c:forEach>等等。它們沒有什麼神秘的地方,就其源頭也還是Java Class而已,Tag標簽的實質也就是一段Java代碼,或者說一個Class文件。當配置文件設置好去哪裡尋找這些Class的路徑後,容器負責將頁面中存在的標簽對應到相應的Class上,執行那段特定的Java代碼,如此而已。
說得明白一點的話還是舉幾個簡單的例子說明一下吧:
<jsp:include>去哪裡找執行什麼class呢?首先這是個jsp類庫的標簽,當然要去jsp類庫尋找相應的class了,同樣它也是由Web容器來提供,例如 Tomcat就應該去安裝目錄的lib文件夾下面的jsp-api.jar裡面找,有興趣的可以去找一找啊!
<c:forEach>又去哪裡找呢?這個是由Jsp2.0版本推薦的和核心標記庫的內容,例如<c:if> 就對應在頁面中做if判斷的功能的一斷Java代碼。它的class文件在jstl.jar這個類庫裡面,往往還需要和一個standard.jar類庫一起導入,放在具體Web項目的WEB-INF的lib目錄下面就可以使用了。
順便羅唆一句,Web Project的目錄結構是相對固定的,因為容器會按照固定的路徑去尋找它需要的配置文件和資源,這個任何一本J2ee入門書上都有,這裡就不介紹了。了解Tag的本質還要了解它的工作原理,所以大家去J2ee的API裡找到並研究這個包:javax.servlet.jsp.tagext.它有一些接口,和一些實現類,專門用語開發Tag,只有自己親自寫出幾個不同功能的標簽,才算是真正理解了標簽的原理。別忘記了自己開發的標簽要自己去完成配置文件,容器只是集成了去哪裡尋找jsp標簽對應class的路徑,自己寫的標簽庫當然要告訴容器去哪裡找啦。
說了這麼多,我們為什麼要用標簽呢?完全在Jsp裡面來個<% %>就可以在裡面任意寫Java代碼了,但是長期實踐發現頁面代碼統一都是與html同風格的標記語言更加有助於美工人員進行開發前台,它不需要懂Java,只要Java程序員給個列表告訴美工什麼標簽可以完成什麼邏輯功能,他就可以專注於美工,也算是進一步隔離了前後台的工作吧!
3.成就Web框架框架是什麼?曾經看過這樣的定義:與模式類似,框架也是解決特定問題的可重用方法,框架是一個描述性的構建塊和服務集合,開發人員可以用來達成某個目標。一般來說,框架提供了解決某類問題的基礎設施,是用來創建解決方案的工具,而不是問題的解決方案。
正是由於Tag的出現,成就了以後出現的那麼多Web框架,它們都開發了自己成熟實用的一套標簽,然後由特定的Xml文件來配置加載信息,力圖使得Web 應用的開發變得更加高效。下面這些標簽相應對很多人來說相當熟悉了:
<html:password>
<logic:equal>
<bean:write>
<f:view>
<h:form>
<h:message>
它們分別來自Struts和JSF框架,最強大的功能在於控制轉發,就是MVC三層模型中間完成控制器的工作。Struts-1實際上並未做到真正的三層隔離,這一點在Struts-2上得到了很大的改進。而Jsf向來以比較完善合理的標簽庫受到人們推崇。
今天就大概講這麼多吧,再次需要強調的是Servlet/Jsp是學習J2ee必經之路,也是最基礎的知識,希望大家給與足夠的重視!