1. 程式人生 > >Servlet 規範與工作原理的簡單理解

Servlet 規範與工作原理的簡單理解

  • Servlet與Servlet容器

    • 容器就是可以接收請求,並將請求轉發到servlet提供的對外服務的方法,比如tomcat 伺服器 接受request請求,再呼叫Servlet的doGet、doPost等方法。

    Servlet
    Servlet是受容器管理的web元件,它能動態地生成內容。Servlet是一段小程式,被編譯成平臺無關、架構中立的的位元組碼之後,可以被 Web伺服器器動態地載入和執行。Servlet通過容器實現的請求-相應(request-response)方式與Web瀏覽器進行互動,這種請求- 相應模式是基於超文字傳輸協議(HTTP)的。
    Servlet容器


    Servlet容器和Web伺服器或者應用伺服器一起提供網路服務,能解析MIME編碼的請求,能生成MIME編碼格式的相應。容器還負責容納servlet,並對其生命週期進行管理。
    Servlet容器可以內建在Web伺服器中,也可以通過web伺服器的擴充套件API作為附加元件安裝。Servlet容器同樣可以作為具體Web服務功能的應用伺服器的內建模組或者附加元件。
    所有的Servlet容器必須支援HTTP協議,並可以支援其他基於請求-相應模式的協議,例如HTTPS。Servlet容器至少需要支援HTTP 1.0版本,並強烈建議同時支援HTTP 1.1版本。

  • Servlet是否單例及執行緒安全問題

    • servlet作為一個Java類,沒有私有構造方法,所以不是單例的類

      Servlet採用多執行緒來處理多個請求同時訪問。servlet依賴於一個執行緒池來服務請求。執行緒池實際上是一系列的工作者執行緒集合。Servlet使用一個排程執行緒來管理工作者執行緒。
      當容器收到一個Servlet請求,排程執行緒從執行緒池中選出一個工作者執行緒,將請求傳遞給該工作者執行緒,然後由該執行緒來執行Servlet的service方法。當這個執行緒正在執行的時候,容器收到另外一個請求,排程執行緒同樣從執行緒池中選出另一個工作者執行緒來服務新的請求,容器並不關心這個請求是否訪問的是同一個Servlet.當容器同時收到對同一個Servlet的多個請求的時候,那麼這個Servlet的service()方法將在多執行緒中併發執行。
      Servlet容器預設採用單例項多執行緒的方式來處理請求,這樣減少產生Servlet例項的開銷,提升了對請求的響應時間,對於Tomcat可以在server.xml中通過元素設定執行緒池中執行緒的數目。
      就實現來說:


      排程者執行緒類所擔負的責任如其名字,該類的責任是排程執行緒,只需要利用自己的屬性完成自己的責任。所以該類是承擔了責任的,並且該類的責任又集中到唯一的單體物件中。而其他物件又依賴於該特定物件所承擔的責任,我們就需要得到該特定物件。那該類就是一個單例模式的實現了。
      注意
      伺服器可以使用多個例項來處理請求,代替單個例項的請求排隊帶來的效益問題。伺服器建立一個Servlet類的多個Servlet例項組成的例項池,對於每個請求分配Servlet例項進行響應處理,之後放回到例項池中等待下此請求。這樣就造成併發訪問的問題。
      此時,區域性變數(欄位)也是安全的,但對於全域性變數和共享資料是不安全的,需要進行同步處理。而對於這樣多例項的情況SingleThreadModel介面並不能解決併發訪問問題。 SingleThreadModel介面在servlet規範中已經被廢棄了。

      • 執行緒安全問題

        1、實現 SingleThreadModel 介面
          該介面指定了系統如何處理對同一個Servlet的呼叫。如果一個Servlet被這個介面指定,那麼在這個Servlet中的service方法將不會有兩個執行緒被同時執行,當然也就不存線上程安全的問題。這種方法只要將前面的Concurrent Test類的類頭定義更改為:

        Public class ConcurrentServletTest extends HttpServlet implements SingleThreadModel { 
                ······
        }     

        2、同步對共享資料的操作
          使用synchronized 關鍵字能保證一次只有一個執行緒可以訪問被保護的區段,在本論文中的Servlet可以通過同步塊操作來保證執行緒的安全。同步後的程式碼如下:

        Public class ConcurrentTest extends HttpServlet {
                Username = request.getParameter ("username"); 
                Synchronized (this){ 
                    Output = response.getWriter (); 
                    Try { 
                        Thread. Sleep (5000); 
                    } Catch (Interrupted Exception e){} 
                        output.println("使用者名稱:"+Username+"<BR>"); 
                } 
            } 
        } 

        3、避免使用例項變數
          本例項中的執行緒安全問題是由例項變數造成的,只要在Servlet裡面的任何方法裡面都不使用例項變數,那麼該Servlet就是執行緒安全的。
          修正上面的Servlet程式碼,將例項變數改為區域性變數實現同樣的功能,程式碼如下:

        Public class ConcurrentTest extends HttpServlet {
                public void service (HttpServletRequest request, HttpServletResponse 
        Response) throws ServletException, IOException { 
                PrintWriter output; 
                String username; 
                Response.setContentType ("text/html; charset=gb2312"); 
            } 
        }