JavaWeb Servlet概要

一、Servlet簡介

Java Servlet 是運行在 Web 服務器或應用服務器上的程序,它是做爲來自 Web 瀏覽器或其餘 HTTP 客戶端的請求和 HTTP 服務器上的數據庫或應用程序之間的中間層。使用 Servlet,能夠收集來自網頁表單的用戶輸入,呈現來自數據庫或者其餘源的記錄,還能夠動態建立網頁。
Servlet是sun公司提供的一門用於開發動態web資源的技術。
Sun公司在其API中提供了一個servlet接口,用戶若想用發一個動態web資源(即開發一個Java程序向瀏覽器輸出數據),須要完成如下2個步驟:
  一、編寫一個Java類,實現servlet接口。
  二、把開發好的Java類部署到web服務器中。
  按照一種約定俗成的稱呼習慣,一般咱們也把實現了servlet接口的java程序,稱之爲Servlet。html

二、Servlet調用機制

Servlet程序是由WEB服務器調用,web服務器收到客戶端的Servlet訪問請求後:
  ①Web服務器首先檢查是否已經裝載並建立了該Servlet的實例對象。若是是,則直接執行第④步,不然,執行第②步。
  ②裝載並建立該Servlet的一個實例對象。
  ③調用Servlet實例對象的init()方法。
  ④建立一個用於封裝HTTP請求消息的HttpServletRequest對象和一個表明HTTP響應消息的HttpServletResponse對象,而後調用Servlet的service()方法並將請求和響應對象做爲參數傳遞進去。
  ⑤WEB應用程序被中止或從新啓動以前,Servlet引擎將卸載Servlet,並在卸載以前調用Servlet的destroy()方法。java

三、Servlet 生命週期

Servlet 生命週期可被定義爲從建立直到毀滅的整個過程。如下是 Servlet 遵循的過程:web

  • Servlet 初始化後調用 init () 方法。
  • Servlet 調用 service() 方法來處理客戶端的請求。
  • Servlet 銷燬前調用 destroy() 方法。
  • 最後,Servlet 是由 JVM 的垃圾回收器進行垃圾回收的。

四、Servlet 任務

Servlet 執行如下主要任務:數據庫

  • 讀取客戶端(瀏覽器)發送的顯式的數據。這包括網頁上的 HTML 表單,或者也能夠是來自 applet 或自定義的 HTTP 客戶端程序的表單。
  • 讀取客戶端(瀏覽器)發送的隱式的 HTTP 請求數據。這包括 cookies、媒體類型和瀏覽器能理解的壓縮格式等等。
  • 處理數據並生成結果。這個過程可能須要訪問數據庫,執行 RMI 或 CORBA 調用,調用 Web 服務,或者直接計算得出對應的響應。
  • 發送顯式的數據(即文檔)到客戶端(瀏覽器)。該文檔的格式能夠是多種多樣的,包括文本文件(HTML 或 XML)、二進制文件(GIF 圖像)、Excel 等。
  • 發送隱式的 HTTP 響應到客戶端(瀏覽器)。這包括告訴瀏覽器或其餘客戶端被返回的文檔類型(例如 HTML),設置 cookies 和緩存參數,以及其餘相似的任務。

五、Servlet實例

@WebServlet(name = "MyServlet", urlPatterns = {"/MyServlet", "/myServlet"})
public class MyServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("----------doPost-----------");
        doGet(request, response);
}

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("----------doGet-----------");
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
        out.println("<HTML>");
        out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
        out.println("  <BODY>");
        out.print("    This is ");
        out.print(this.getClass());
        out.println(", using the GET method");
        out.println("  </BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }
}

六、Servlet註冊方式

6.一、web.xml方式(傳統方式)

<servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>org.silence.servlet.MyServlet</servlet-class>
    <init-param>
        <param-name>name</param-name>
        <param-value>zhangsan</param-value>
    </init-param>
    <display-name>MyServlet</display-name>
</servlet>
<servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/servlet</url-pattern>
</servlet-mapping>

6.二、@WebServlet註解方式(servlet3.0開始)

注意:Servlet3.0的項目服務器須要Tomcat7.0開始的版本才支持!!瀏覽器

@WebServlet(name = "ParamServlet",
        urlPatterns = "/param",
        initParams = {@WebInitParam(name = "name", value = "zhangsan"), @WebInitParam(name = "abc", value = "abc")})
public class ParamServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = getServletContext();
        ServletConfig config = getServletConfig();
        String name = config.getInitParameter("name");
        response.getWriter().println(name);

        Enumeration<String> parameterNames = config.getInitParameterNames();
        while (parameterNames.hasMoreElements()) {
            String element = parameterNames.nextElement();
            String parameter = config.getInitParameter(element);
            response.getWriter().println(element + " = " + parameter);
        }
    }
}

七、Servlet線程安全

在默認的狀況下Servlet容器(web服務器)對聲明的Servlet,只建立一個Servlet實例,當多個客戶端併發訪問同一個Servlet時,Servlet容器會爲每個客戶端的訪問請求建立一個線程,並在這個線程上調用Servlet的service方法,所以service方法內若是訪問了同一個資源的話,就有可能引起線程安全問題。

例以下面的代碼:緩存

@WebServlet(name = "SynServlet", urlPatterns = "/syn")
public class SynServlet extends HttpServlet {
    int i = 1;

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        synchronized (this) {
        i++;
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        response.getWriter().write("i: " + i);
//        }
    }
}

解決辦法之一是給共享資源加鎖。安全

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    synchronized (this) {
        i++;
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        response.getWriter().write("i: " + i);
    }
}

7.一、Servlet線程安全的解決方式

7.1.一、實現javax.servlet.SingleThreadModel接口(不推介)

javax.servlet.SingleThreadModel API及其翻譯服務器

  Ensures that servlets handle only one request at a time. This interface has no methods.cookie

  確保servlet每次只處理一項請求。接口不含方法。session

  If a servlet implements this interface, you are guaranteed that no two threads will execute concurrently in the servlet's service method. The servlet container can make this guarantee by synchronizing access to a single instance of the servlet, or by maintaining a pool of servlet instances and dispatching each new request to a free servlet.

  *若是servlet實現了該接口,會確保不會有兩個線程同時執行servlet的service方法。 servlet容器經過同步化訪問servlet的單實例來保證,也能夠經過維持servlet的實例池,對於新的請求會分配給一個空閒的servlet。*

  Note that SingleThreadModel does not solve all thread safety issues. For example, session attributes and static variables can still be accessed by multiple requests on multiple threads at the same time, even when SingleThreadModel servlets are used. It is recommended that a developer take other means to resolve those issues instead of implementing this interface, such as avoiding the usage of an instance variable or synchronizing the block of the code accessing those resources. This interface is deprecated in Servlet API version 2.4.

  *注意:SingleThreadModel不會解決全部的線程安全隱患。*例如,會話屬性和靜態變量仍然能夠被多線程的多請求同時訪問,即使使用了SingleThreadModel servlet。

7.1.二、同步共享資源(推介)

使用synchronized或提供的鎖來同步共享資源。

7.1.三、避免使用實例變量
相關文章
相關標籤/搜索