JavaWeb學習之Servlet(三)----Servlet的映射匹配問題、線程安全問題


【聲明】

歡迎轉載,但請保留文章原始出處→_→

文章來源: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的響應速度。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM