第一章
servlet2.3規范用到了一下的一些規范:J2EE、JSP1.1、JNDI
在14章中講述了規范中的所有的classes類或接口(改文中不講述)。對開發者而言以下的有些相關的
協議:URI、URL、HTTP/1.0、MIME、HTCPCP/1.0、XML
1.1 什么是servlet?
servlet是一個基于java技術的web組件,該組件被容器管理,能被編譯成字節碼被web服務調
用;容器也被稱之為引擎,是支持servlet功能的web服務的擴展。servlet之間的通信是通過客戶
端請求被引擎執行成request/response對象進行的。
1.2 什么是servlet引擎?
servlet引擎是web服務器或應用服務器的一部分,服務器能夠支持網絡的請求/響應,基于請求
解析MIME,基于響應格式化MIME。servlet引擎是一個servlet容器,也掌管著servlet的生命周
期。
所有的servlet引擎都必須支持HTTP的請求/響應模式,但HTTPS的請求/響應模式也是被支持
的。HTTP的版本最小要HTTP/1.0,最好是HTTP/1.1。servlet引擎也具有安全和權限的一些特
性,這些特性其服務器應提供。
1.3 例子
一個典型的事件執行的順序是:
1) 客戶端向web服務器發起一個HTTP請求
2) HTTP請求被web服務器接受,并移交給servlet引擎,servlet引擎可以在主機的
同一個進程、不同的進程或其他的web服務主機的進程中啟動。
3) servlet引擎根據servlet的配置檔確定調用的servlet,并把request對象、
response對象傳給它。
4) 4.servlet通過request對象知道客戶端的使用者是誰,客戶的請求信息是什么
和其他的一些信息。servlet處理完請求后把要返回的信息放入response對象返回到
客戶端
5) 一旦servlet完成了請求的處理,servlet引擎就會刷新response,把控制權返回給
web服務器
1.4與其它技術的比較
與其它服務相比servlet有以下的一些優點
1) 運行速度上比CGI快,因為使用了多線程
2) servlet使用了標準的api,可被許多web服務支持
3) 與系統無關性,一次編譯多次使用
第二章
servlet接口是servlet api核心部分,所有的servlet都是直接或間接的實現了這些接口。兩個最重
要的servlet api 接口是GenericServlete 和 HttpServlet,更多的開發者都繼承HttpServlet去實現
他們的servlet
2.1 Request 包含的方法
一個基本的servlet接口應該定義一個方法包含客戶端的信息,每次servlet引擎把一個request發
送到一個servlet事例,這個方法都要被調用。
對于并發的請求,web應用需要設計者設計的servlet引擎能分配多個線程執行這個方法。
2.1.1 HTTP 請求處理的方法
HttpServlet是實現了Servlet接口的抽象類,增加了一些新的方法,這些方法在處理HTTP請求時
會被service方法自動調用,這些方法是:
doGet 接受 HTTP 的GET請求
doPost 接受 HTTP 的POST請求
doPut 接受 HTTP的PUT請求
doDelete 接受 HTTP的DELETE請求
doHead 接受 接受 HTTP的HEAD請求
doOptions 接受 HTTP的OPTIONS請求
doTrace 接受 HTTP的TRACE請求
一個開發者只會涉及到doGet和doPost方法,其它的方法是為非常熟悉HTTP的設計師準備的
2.1.2
HTTP/1.0只定義了doGet,doHead,doPost方法,沒有定義PUT,DELETE,OPTIOONS和
TRACE方法
2.1.3
HttpServlet接口定義了getLastModified方法
2.2 實例數
2.2.1
在分布式環境中servlet引擎為每個servlet只能聲明一個實例,當一個servlet實現了
SingleThreadModel接口時,servlet引擎可以聲明多個實例去處理請求,servlet在應用服務的部
署描述中定義發布.
2.2.2單線程servlet
SingleThreadModel接口保證了在同一時刻一個servlet實例的service方法只會被一個線程執行。
這對于每個請求發送給每個實例是很重要的。引擎可以從對象池中選擇,對象池可以在同一時
刻保持多個實例,如HttpSession可以被多個servlet在任何時候調用包括實現了
SingleThreadModel接口的servlet
2.3 servlet的生命周期
一個好的生命周期的定義應該是servlet怎么被引入了,怎么實例化的,怎么初始化的?當請求從客
戶端來的時候,是怎么從服務器中取出來的,這些在javax.servlet.Servlet的接口的init,service,
destroy方法中都有明確的定義。
所有的servlet都必須實現GenericServlet或HttpServlet抽象類
2.3.1 servlet的引入和實例化
servlet引擎會可靠的引入和實例化servlet,當servlet引擎被啟動時servlet就被引入和實例化了,
或者當一個servlet被請求時被引擎引入和實例化。
servlet引擎啟動時,需要裝載的類通過java的裝載類進行裝載,被裝載的類可以在本地文件系
統、遠程文件系統或網絡服務中。在裝載完后,引擎就實例化它們。
2.3.2 初始化
在servlet對象實例化后,引擎必須在這個servlet接受客戶段請求之前初始化,在初始化中
servlet可以讀取固定的配置信息,一些昂貴的資源如數據庫連接和一次性激活的資源,引擎通
過調用servlet接口的init方法初始化。每個serlet對象都實現了Servlet接口和ServletConfig接口,
ServletConfig接口允許servlet接受web應用配置檔中配置的參數,還向servlet中傳入了一個描述
servlelt運行環境的類(ServletContext)
2.3.2.1 在初始化時發生錯誤
在初始化過程中,servlet實例能拋出UnavailableException 或ServletException異常。在這樣的
情況下servlet不能被放入服務中,必須被引擎釋放,destroy方法沒有被調用。在初始化失敗后
引擎可以在UnavailableException異常規定的最短無效時間后實例化新的一個實例,再初始化。
2.3.3 request
當servlet初始化完成后,引擎可以使用它去處理客戶端的請求了。請求被封裝在Servletrequest
類型的對象中,響應信息被封裝在ServletResponse類型的對象中,這兩個對象以參數的形式傳
給Servlet接口中的service方法。
2.3.3.1 多線程問題
servlet引擎可以發送并發的請求給servlet的service方法,servlet開發者必須提供足夠的線程來
運行service方法。
對開發者來說一個可以選擇的方法是實現SingleThreadModel接口,以確保在同一時刻只有一個
請求在service方法中。一個引擎要確保請求能夠在servlet中持續化,或維持在一個servlet實例
池中,如果servlet是web應用服務的一部分,引擎可以在一個虛擬機中擁有一個servlet實例化的
池。
對于沒有實現SingleThreadModel接口的servlet,如果service方法(或 doGet,doPost)被聲明
為synchronized,引擎將不能用實例池的途徑,而必須持續化請求,強力建議開發者不能聲明
synchronize service方法,這樣會嚴重影響系統的性能。
2.3.3.2 request中的異常
在處理請求時servlet可以拋出ServletException或UnavailableException異常,一個
ServletException異常會在處理一個請求出現錯誤時拋出,引擎將清除這個異常。當servlet一時
或永久地不能獲得一個請求時就會拋出UnavailableException異常,如果是一個永久性異常時引擎
將調用它的destroy方法從服務器中消除servlet實例,如果是暫時性異常時引擎在異常期間不發
送請求給servlet。如果返回SERVICE_UNAVAILABLE(503)響應,在這期間引擎將不接受任何請
求,直到header中出現Retry-After。引擎可以不區分永久性還是暫時性的異常把所有的
UnavailableException作為永久性處理。
2.3.3.3 線程安全
執行request和response對象不能保證是線程安全的,意思是說他們只能在請求的線程中使用,
不能被其它線程中的對象使用。
2.3.4 結尾
servlet實例可能被引擎保存幾毫秒或和引擎一樣的生命時間或在這兩者之間。當引擎決定結束
一個servlet時,調用它的destroy方法,在destroy中釋放任何長久固定的資源。
在引擎調用desroy方法之前,必須保證運行在service方法中的線程都完成處理,或者超過了服
務定義的執行時間。
一旦servlet實例的destroy方法被調用,引擎不在發送任何請求給這個實例。如果引擎再次使用
這個servlet就必須再建一個這個servlet的實例。
在destroy方法執行完成后,引擎將釋放這個servlet實例,于是就符合垃圾回收機制的條件了。
第三章3.1 介紹ServletContext接口
ServletContext接口定義了servlet運行環境的信息。引擎提供商有義務在servlet引擎中提供一個
實現了ServletContext接口的對象。通過這個對象servlet能夠獲得log事件,資源的URL,設置或
存儲servlet之間通信的變量。ServletContext在web服務中確定了一個所有請求開始的路徑,是
ServletContext的上下文路徑。
3.2 ServletContext 接口的作用范圍
每個web應用配置到容器中都會產生一個實現了ServvletContext接口的實例。如果是分布式
的,將會在每個java虛擬機上產生一個ServletContext實例。容器中默認固有的web應用(不是
發布上來的web應用)有一個默認的ServletContext,在分布式中這個默認的ServletContext只存
在于一個虛擬機中,是不可分配的。
3.3 初始化參數
ServletContext接口的getInitParameter,getInitParameterNames方法接受部署描述文件中的初始
化參數,這些參數可以是的安裝信息,或網站管理員的mail或名字或對系統的評論。
3.4 上下文屬性
servlet可以通過一個名稱把對象邦定到servletContext中,幫定到ServletContext中的對象都能被
同一個web服務中的其它對象引用。ServletContext中的屬性方法有:
setAttribute
getAttribute
getAttributeNames
removeAttribute
3.4.1 在分布式系統中 上下文的屬性
上下文屬性是在本地的虛擬機中保存的,這防止了ServletContext屬性存在于分布式的內存中。
當信息需要在一個分布式環境中共享的時候,信息應該被放在session中,或存在數據庫中,或
存在一個實體bean中。
3.5 資源
ServletContext接口提供了獲取web服務中的靜態資源的方法:
getResource
getResourceAsStream
這些方法以一個“/”作為上下文的根目錄,后跟著資源路徑的路徑為參數。這些資源可以在本地
服務系統中也可以在另個web應用中,或在一個遠程的文件系統中。
這些方法不能用于去獲得一個動態的資源,如要調用一個jsp頁面,getResource("/index.jsp")將
返回index.jsp的原代碼,不能web顯示index.jsp。
要獲得資源列表可以用getResourcePaths(String path)方法
3.6 多主機 和 Servlet 上下文
web服務中可能在一個IP上有多個邏輯主機的情況。在這種情況下每個邏輯主機必須有自己單
獨的servlet上下文,或者設置多個servlet 上下文,但在邏輯主機中不能共享這些servlet 上下
文,一個主機只能單獨使用一個。
3.7
引擎提供類重新裝載機制是必須的,必須確認應用中所有的類和接口都可以在單類裝載器中
裝載;在session綁定監聽事件中引擎會終止正在裝在的類。以前版本的裝載器,引擎創建一
個新的裝載器裝載一個servlet或class和類裝載器裝載其他的servlet或類截然不同;這可能裝
載一個未知的類或對象,產生不可預知的行為。這是新的類裝載器中是應該注意預防的問
題。
3.7.1 臨時工作目錄
Servlet 上下文需要一個臨時存儲的目錄。servlet引擎必須為每個servlet 上下文提供一個私有臨
時目錄,通過javax.servlet.context.tempdir的context屬性使目錄有效。與該屬性關聯的對象必
須是java.io.File類型。
在許多servlet引擎實現中提供請求可以識別的通用的機制。
當servlet引擎重起始不必維護臨時目錄中的內容,但要確保臨時目錄中的該上下文內容對于運
行在該servlet引擎中的其它web應用中的servlet 上下文是不可見的。