servlet

這部分結合之前的幾章一起看,以免遺漏。

http://blog.163.com/qqabc20082006@126/blog/static/2292852520106249123739/

Servlet

什麼是Servlet

       Servlet是一個JavaEE組件,是在服務器端運行處理客戶端請求並作出響應的程序。


Servlet何時被創建

  1,默認情況下,當WEB客戶第一次請求訪問某個Servlet的時候,WEB容器將創建這個Servlet的實例。

  2,當web.xml文件中如果<servlet>元素中指定了<load-on-startup>子元素時,Servlet容器在啓動web服務器時,將按照順序創建並初始化Servlet對象。

  注意:在web.xml文件中,某些Servlet只有<serlvet>元素,沒有<servlet-mapping>元素,這樣我們無法通過url的方式訪問這些Servlet,這種Servlet通常會在<servlet>元素中配置一個<load-on-startup>子元素,讓容器在啓動的時候自動加載這些Servlet並調用init()方法,完成一些全局性的初始化工作。


 http://www.cnblogs.com/cuiliang/archive/2011/10/21/2220671.html

Servlet的執行過程

首先,客戶端發送請求到服務器端;

其次,服務器端根據web.xml文件中的Servlet相關配置信息,將客戶端請求轉發到相應的Servlet;

之後,Servlet會根據request對象中封裝的用戶請求與數據庫進行交互,返回數據之後,Servlet會將返回的數據封裝到response對象中;

此時,控制權從Servlet重新回到服務器端,最後,服務器端將響應信息返回給客戶端,並且跳轉到相應的頁面。

 

Servlet生命週期分爲三個階段:

  1,初始化階段  調用init()方法

  2,響應客戶請求階段  調用service()方法

  3,終止階段  調用destroy()方法

Servlet初始化階段

  在下列時刻Servlet容器裝載Servlet:

    1,Servlet容器啓動時自動裝載某些Servlet,實現它只需要在web.XML文件中的<Servlet></Servlet>之間添加如下代碼: 

             <loadon-startup>1</loadon-startup>

    2,在Servlet容器啓動後,客戶首次向Servlet發送請求

    3,Servlet類文件被更新後,重新裝載Servlet

  Servlet被裝載後,Servlet容器創建一個Servlet實例並且調用Servlet的init()方法進行初始化。

        在Servlet的整個生命週期內,init()方法只被調用一次。

    

Servlet響應請求階段

  對於用戶到達Servlet的請求,Servlet容器會創建特定於這個請求的ServletRequest對象和ServletResponse對象,然後調用Servlet的service方法。service方法從ServletRequest對象獲得客戶請求信息,處理該請求,並通過ServletResponse對象向客戶返回響應信息。

  對於Tomcat來說,它會將傳遞過來的參數放在一個Hashtable中,該Hashtable的定義是:

private Hashtable<String String[]> paramHashStringArray = newHashtable<String String[]>();

  這是一個String-->String[]的鍵值映射。

  HashMap線程不安全的,Hashtable線程安全。

-----------------------------------------------------------------------------------------------------------------------------------

Servlet終止階段

  當WEB應用被終止,或Servlet容器終止運行,或Servlet容器重新裝載Servlet新實例時,Servlet容器會先調用Servlet的destroy()方法,在destroy()方法中可以釋放掉Servlet所佔用的資源。


Servlet類的繼承關係

         客戶發送一個請求,Servlet是調用service()方法對請求進行響應的。

         通過源代碼可見,service()方法中對請求的方式進行了匹配,選擇調用doGet,doPost等這些方法,然後再進入對應的方法中調用邏輯層的方法,實現對客戶的響應。


         在Servlet接口和GenericServlet中是沒有doGet,doPost等等這些方法的,HttpServlet中定義了這些方法,但是都是返回error信息,所以,我們每次定義一個Servlet的時候,都必須實現doGet或doPost等這些方法。

   每一個自定義的Servlet都必須實現Servlet的接口,Servlet接口中定義了五個方法,其中比較重要的三個方法涉及到Servlet的生命週期,分別是上文提到的init(),service(),destroy()方法。

        GenericServlet是一個通用的,不特定於任何協議的Servlet,它實現了Servlet接口。

        而HttpServlet繼承於GenericServlet,因此HttpServlet也實現了Servlet接口。所以我們定義Servlet的時候只需要繼承HttpServlet即可。

  Servlet接口和GenericServlet是不特定於任何協議的,而HttpServlet是特定於HTTP協議的類,所以HttpServlet中實現了service()方法,並將請求ServletRequest,ServletResponse強轉爲HttpRequest和HttpResponse。


public void service(ServletRequest req,ServletResponse res)
  throwsServletException,IOException
{
      HttpRequest request;
      HttpResponse response;
 
     try
     {
         req = (HttpRequest)request;
         res = (HttpResponse)response;
      }catch(ClassCastException e)
      {
         thrownewServletException("non-HTTP request response");
      }
      service(request,response);
}

         代碼的最後調用了HTTPServlet自己的service(request,response)方法,然後根據請求去調用對應的doXXX方法,因爲HttpServlet中的doXXX方法都是返回錯誤信息,

protectedvoiddoGet(HttpServletRequest res,HttpServletResponse resp)
  throwsServletException,IOException
{
   String protocol = req.getProtocol();
   String msg = IStrings.getString("http.method_get_not_supported");
   if(protocol.equals("1.1"))
   {
      resp.sendError(HttpServletResponse.SC.METHOD.NOT.ALLOWED,msg);
    }
   esle
    {
      resp.sendError(HttpServletResponse.SC_BAD_REQUEST,msg);
    }
}

        所以需要我們在自定義的Servlet中override這些方法!


        Servlet的實現:Servlet接口->GenericServlet類->HttpServlet類->用戶自定義的Servlet

Servlet與JSP的關係及區別

Servlet是JSP的基礎,JSP是Servlet技術的擴展。JSP運行之前首先將編譯爲一個Servlet。

JSP側重於視圖;Servlet主要用於控制業務邏輯。



Servlet API中的forward()redirect()的區別?

請求轉發:forward是Request對象的方法,它是在服務器端執行,並且始終在同一個Request域中,所以頁面間可以共享Request對象中的資源。轉發後,客戶端瀏覽器地址不會改變;請求轉發性能優於重定向;

<jsp:forward>

servlet中的實現:

RequestDispatcher rd = request.getRequestDispatcher("login2");

rd.forward(request, response);-----------------服務器端將request和response對象直接轉發給目的servlet處理。reques不變。


重定向:redirect是response對象的方法,發生在客戶端瀏覽器,它有兩次Request請求,第二次請求將丟失第一次Request中的資源。重定向之後,客戶端瀏覽器地址發生改變。

servlet中的實現:response.sendRedirect("error.jsp");----------------響應發給客戶端,客戶端再向"error.jsp"發出請求。request改變。



 

Servlet API中的include()

<jsp:include>

servlet中的實現:

RequestDispatcher rd = request.getRequestDispatcher("login2");

rd.include(request, response);-----------------服務器端將request和response對象直接交給被包含的servlet處理。reques不變。




Servlet是單實例的,但有兩種訪問模式:多線程以及單線程訪問,前者會有線程安全方面的問題,後者有請求排隊等待的問題。


Servlet如何同時處理多個請求?

        Servlet採用多線程來處理多個請求的同時訪問。Servlet容器通過線程池來管理維護服務請求。所謂線程池,相當於數據庫連接池,實際上是等待執行代碼的一組線程,叫做工作者線程。Servlet容器通過一個調度線程來管理工作者線程。

· 當容器收到一個Servlet的訪問請求,調度者線程就從線程池中選出一個工作者線程,將用戶請求傳遞給該線程,然後由該線程處理Servlet的service()方法;

· 當這個線程在執行的時候,容器收到一個新的請求,調度者線程再次從線程池中選出一個新的工作者線程;

· 當容器同時收到對同一個Servlet的多個請求時,那麼Servlet的service方法將在多線程中併發執行。

注:1.Servlet容器默認採用單實例多線程的方式來處理請求。這樣減少了產生Sevlet實例的開銷,提升了對請求的響應時間;

       2.對於Tomcat容器來講,可以在其server.xml中通過<Connector>中設置線程池中的線程數目。

Servlet也可以採用單線程模式!

 

如何開發線程安全的Servlet

       Servlet容器採用多線程來處理請求,提高性能的同時也造成了線程安全問題。要開發線程安全的Servlet應該從一下幾個方面進行:

1. 變量的線程安全; 多線程並不共享局部變量,所以我們要儘可能的在Servlet中使用局部變量;

2. 代碼塊的線程安全; 使用同步塊Synchronized,防止可能調用的代碼塊;但是要注意的是,要儘可能得縮小同步代碼的方範圍,不要在service方法和響應方法上直接使用同步,這會嚴重影響性能。

3.  屬性的線程安全;ServletContext,HttpSession,ServletRequest對象中屬性;

4. 使用同步集合; 使用Vector代替ArrayList,使用HashTable代替HashMap;

5. 不要在Servlet中創建自己的線程來完成某個功能; Servlet本身就是多線程的,如果再創建新的線程,將會導致線程執行複雜化,出現線程安全問題;

6. 在多個Servlet中,對外部對象,比如:文件;進行修改操作一定要加鎖,做到互斥訪問;

 

如何實現servlet的單線程模式?

javax.servlet.SingleThreadModel接口是一個標識接口,如果一個Servlet實現了這個接口,那Servlet容器將保證在一個時刻僅有一個線程可以在給定的servlet實例的service方法中執行,將其他所有請求進行排隊。實現方法:<%@ page isThreadSafe="false" %>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章