Servlet規范
一個最基本的 Java Web 項目所需的 jar 包只需要一個 servlet-api.jar ,這個 jar 包中的類大部分都是接口,還有一些工具類,共有 2 個包,分別是 javax.servlet 和 javax.servlet.http。所有的 Servlet 容器都帶有這個包,你無需再放到Web項目里,放到這里只不過是編譯的需要,運行是不需要的。如果你硬是把 servlet-api.jar 放到 webapp/WEB-INF/lib 目錄下,那么 Tomcat 啟動時還會報一個警告信息。
Servlet 是 J2EE 最重要的一部分,有了 Servlet 你就是 J2EE 了,J2EE 的其他方面的內容擇需采用。而
Servlet 規范你需要掌握的就是 servlet 和 filter 這兩項技術。絕大多數框架不是基於 servlet 就是基於 filter,如果它要在 Servlet 容器上運行,就永遠也脫離不開這個模型。
為什么 Servlet 規范會有兩個包,javax.servlet 和 javax.servlet.http ,早先設計該規范的人認為 Servlet 是一種服務模型,不一定是依賴某種網絡協議之上,因此就抽象出了一個 javax.servlet ,同時在提供一個基於 HTTP 協議上的接口擴展。但是從實際運行這么多年來看,似乎沒有發現有在其他協議上實現的 Servlet 技術。
Servlet 規范其實就是對 HTTP 協議做面向對象的封裝,HTTP協議中的請求和響應就是對應了 HttpServletRequest 和 HttpServletResponse 這兩個接口。
可以通過 HttpServletRequest 來獲取所有請求相關的信息,包括 URI、Cookie、Header、請求參數等等,別無它路。因此當你使用某個框架時,你想獲取HTTP請求的相關信息,只要拿到 HttpServletRequest 實例即可。
而 HttpServletResponse接口是用來生產 HTTP 回應,包含 Cookie、Header 以及回應的內容等等。
HTTP 協議里是沒有關於 Session 會話的定義,Session 是各種編程語言根據 HTTP 協議的無狀態這種特點而產生的。其實現無非就是服務器端的一個哈希表,哈希表的Key就是傳遞給瀏覽器的名為 jsessionid 的 Cookie 值。
當需要將某個值保存到 session 時,容器會執行如下幾步:
a. 獲取 jsessionid 值,沒有的話就生成一個,也就是 request.getSession() 這個方法
b. 拿到的 HttpSession 對象實例就相當於一個哈希表,你可以往哈希表里存放數據(setAttribute)
c. 你也可以通過 getAttribute 來獲取某個值
而這個名為 jsessionid 的 Cookie 在瀏覽器關閉時會自動刪除。把 Cookie 的 MaxAge 值設為 -1 就能達到瀏覽器關閉自動刪除的效果。
在 servlet 中有一個包 javax.servlet.jsp 是跟 JSP 相關的一些接口規范定義。JSP 比 Servlet 方便的地方在於可直接修改立即生效,不像 Servlet 修改后必須重啟容器才能生效。
因此 JSP 適合用來做視圖,而 Servlet 則適合做控制層。
Servlet線程安全
servlet中默認線程不安全,單例多線程,因此對於共享的數據(靜態變量,堆中的對象實例等)自己維護進行同步控制,不要在service方法或doGet等由service分派出去的方法,直接使用synchronized方法,很顯然要根據業務控制同步控制塊的大小進行細粒度的控制,將不影響線程安全的耗時操作移出同步控制塊;
針對Servlet的線程安全問題,Sun公司是提供有解決方案的:讓Servlet去實現一個SingleThreadModel接口,如果某個Servlet實現了SingleThreadModel接口,那么Servlet引擎將以單線程模式來調用其service方法。
查看Sevlet的API可以看到,SingleThreadModel接口中沒有定義任何方法和常量,在Java中,把沒有定義任何方法和常量的接口稱之為標記接口,經常看到的一個最典型的標記接口就是"Serializable",這個接口也是沒有定義任何方法和常量的,標記接口在Java中有什么用呢?主要作用就是給某個對象打上一個標志,告訴JVM,這個對象可以做什么,比如實現了"Serializable"接口的類的對象就可以被序列化,還有一個"Cloneable"接口,這個也是一個標記接口,在默認情況下,Java中的對象是不允許被克隆的,就像現實生活中的人一樣,不允許克隆,但是只要實現了"Cloneable"接口,那么對象就可以被克隆了。
讓Servlet實現了SingleThreadModel接口,只要在Servlet類的定義中增加實現SingleThreadModel接口的聲明即可。
對於實現了SingleThreadModel接口的Servlet,Servlet引擎仍然支持對該Servlet的多線程並發訪問,其采用的方式是產生多個Servlet實例對象,並發的每個線程分別調用一個獨立的Servlet實例對象。
實現SingleThreadModel接口並不能真正解決Servlet的線程安全問題,因為Servlet引擎會創建多個Servlet實例對象,而真正意義上解決多線程安全問題是指一個Servlet實例對象被多個線程同時調用的問題。事實上,在Servlet API 2.4中,已經將SingleThreadModel標記為Deprecated(過時的)。
Servlet(Filter)中的url-pattern
Serlvet和Filter有三種不同的匹配規則:
(1)精確匹配:/foo;
(2)路徑匹配:/foo/*;
(3)后綴匹配:*.html;
Serlvet的匹配順序是:
首先進行精確匹配;如果不存在精確匹配的進行路徑匹配;最后根據后綴進行匹配;一次請求只會匹配一個Servlet;(Filter是只要匹配成功就添加到FilterChain)
PS:其他寫法(/foo/,/*.html,*/foo)都不對;“/foo*”不能匹配/foo,/foox;