終于正式進入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必經之路,也是最基礎的知識,希望大家給與足夠的重視!