【聲明】
歡迎轉載,但請保留文章原始出處→_→
文章來源:http://www.cnblogs.com/smyhvae/p/4140529.html
一、Servlet映射匹配問題:
在第一篇文章中的第四段(MyEclipse及Tomcat的配置)已經講到這個知識,現在再細化一下:
由於客戶端是通過URL地址訪問web服務器中的資源,所以Servlet程序若想被外界訪問,必須把servlet程序映射到一個URL地址上,這個工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。
<servlet>元素用於注冊Servlet,它包含有兩個主要的子元素:<servlet-name>和<servlet-class>,分別用於設置Servlet的注冊名稱和Servlet的完整類名。
一個<servlet-mapping>元素用於映射一個已注冊的Servlet的一個對外訪問路徑,它包含有兩個子元素:<servlet-name>和<url-pattern>,分別用於指定Servlet的注冊名稱和Servlet的對外訪問路徑。例如:
<servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.vae.servlet.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/servlet/MyServlet</url-pattern> </servlet-mapping>
需要注意的是:
1、一個<servlet>可以對應多個<serlvet-mapping>,從而一個Servlet可以有多個路徑來訪問
2、url-partten中的路徑也可以使用*通配符,但是只能有兩種固定的格式:一種格式是“*.擴展名”,另一種格式是以正斜杠(/)開頭並以“/*”結尾。
由於*的引入,有可能一個路徑被多個urlpartten匹配,這是優先級判斷條件如下:
- 哪個越精確找哪個
- *.后綴的格式永遠匹配級最低
【舉例】
對於如下的一些映射關系:
- Servlet1 映射到 /abc/*
- Servlet2 映射到 /* (表示任何路徑都能匹配)
- Servlet3 映射到 /abc
- Servlet4 映射到 *.do
問題:
- 當請求URL為“/abc/a.html”時,“/abc/*”和“/*”都匹配,哪個servlet響應?Servlet引擎將調用Servlet1。
- 當請求URL為“/abc”時,“/abc/*”和“/abc”都匹配,哪個servlet響應?Servlet引擎將調用Servlet3。
- 當請求URL為“/abc/a.do”時,“/abc/*”和“*.do”都匹配,哪個servlet響應?Servlet引擎將調用Servlet1。
- 當請求URL為“/a.do”時,“/*”和“*.do”都匹配,哪個servlet響應?Servlet引擎將調用Servlet2。
- 當請求URL為“/xxx/yyy/a.do”時,“/*”和“*.do”都匹配,哪個servlet響應?Servlet引擎將調用Servlet2。
3、可以在<serlvet>標簽里配置<load-on-startup>可以用來指定啟動順序。Servlet默認是在第一次被訪問的時候創建,如果配置了這個標簽,就會隨着Web應用的啟動而創建。舉例:
<servlet> <servlet-name>Servlet2</servlet-name> <servlet-class>Servlet2</servlet-class> <load-on-startup>2</load-on-startup> </servlet>
第4行的int值表示多個serlvet的啟動順序。
4、缺省Servlet:
如果有一個Servlet的url-partten被配置為了一根正斜杠"/",這個Servlet就變成了缺省Serlvet.其他Servlet都不處理的請求,由缺省Servlet來處理.
其實對於靜態資源的訪問就是由缺省Servlet來執;設置404頁面、500頁面等提示頁面也是由缺省Servlet來執行。通常我們不會自己去配置缺省Servlet
二、線程安全問題
Servlet引擎采用多線程模式運行,它為並發的每個訪問請求都使用一個獨立的線程來進行響應。
由於默認情況下Servlet在內存中只有一個對象,當多個瀏覽器並發訪問Servlet時就有可能產生線程安全問題。
面試題目注意:Servlet線程不安全,自始至終只維護一個實例。
注:線程安全本質即:同一個資源被多個線程同時操作,可能會互相干擾。
解決方案:
1、SingleThreadModel接口(標記接口,單線程模型接口):不能真的防止線程安全問題(已過時)
Servlet實現了SingleThreadModel接口,那么Servlet引擎將以單線程模式來調用Servlet的service方法。對於實現了SingleThreadModel接口的Servlet,Servlet引擎仍然支持對該Servlet的多線程並發訪問,其采用的方式是產生多個Servlet實例對象,並發的每個線程分別調用獨立的一個Servlet實例對象。
注:此接口在API 2.4中就已經過時,雖然解決了線程安全問題,但是消耗了大量性能(不同的客戶端同時訪問會創建不同的Servlet實例),所以此方法建議不用,實際開發中也不用。
2、使用同步代碼塊:效率降低
下列需要考慮線程安全問題:(多個線程同時訪問數據時)
- 訪問成員變量時(所以,在Servlet中定義成員變量時,需要考慮線程安全問題)
- 訪問共享資源時
注:Servlet中盡量不要使用成員變量。
代碼舉例:訪問成員變量時,要考慮線程安全問題
1 public class MyServlet1 extends HttpServlet { 2 private static final long serialVersionUID = 1L; 3 4 public int count = 10;// 在Servlet中定義成員變量,需要考慮線程安全問題 5 6 public MyServlet1() { 7 super(); 8 } 9 10 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 11 doPost(request, response); 12 } 13 14 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 15 16 synchronized (this) { 17 count ++; 18 } 19 } 20 21 }
最終解決方案:在Servlet中盡量少用類變量(成員變量),如果一定要用類變量則用鎖來防止線程安全問題,但是要注意鎖住內容應該是造成線程安全問題的核心代碼,盡量的少鎖主內容,減少等待時間提高servlet的響應速度。