Web核心-Servlet

glmapper發表於2017-09-17

Servlet實際上是ServerApplet--小服務程式或服務聯結器,用Java編寫的伺服器端程式,主要功能在於互動式地瀏覽和修改資料,生成動態Web內容。與常用的協議,如DNS,TCP/IP,HTTP類似,Servlet是作為一整套規範存在的;同時作為J2EE標準的一部分,定義了javaweb開發的標準。Servlet制定了java處理WEB請求的一系列標準,我們只需要按照標準規定的去做就可以了。
實際上,無論是Struts2的FilterDispatcher還是SpringMvc的DispatcherServlet,其底層都是通過實現Sevlet或者Servlet型別的擴充套件【如:GenericServlet】來實現的。

1.Servlet介面

下圖為Servlet3.1中的結構圖:


因為Servlet是以規範的方式存在的,實際上就是定義一系列規範介面。在Servlet介面中,主要包括以下幾個介面:

1)init方法是在容器啟動時被容器呼叫,且只會被呼叫一次;
2)getServletConfig方法用於獲取ServletConfig;
3)service方法用於處理一個具體的請求
4)getServletInfo方法用於獲取Servlet相關的資訊:版權等。
5)destroy方法用來銷燬一個Servlet,和init一樣,只會被呼叫一次,一般在伺服器關閉時用於釋放一些資源。

init方法呼叫時會接受一個ServletConfig型別的引數,用於初始化Servlet,由容器傳入。ServletConfig,顧名思義,其包含了Serlvet的配置資訊。通常情況下,我們在web.xml檔案中定義Serlvet時,會通過init-param標籤來進行引數配置。在Springmvc的配置中,通常通過以下方式來配置引數:

2.ServletConfig介面


1)getServletName用於獲取Servlet的名字,也就是我們在web.xml中定義的servlet-name
2)getServletContext返回ServletContext,代表我們當前應用本身
3)getInitParameter用於獲取init-param配置的引數
4)getInitParameterNames用於獲取所有init-param配置名字的集合
ServletContext和ServletConfig最常見的使用就是傳遞初始化引數。來看下spring中的contextConfigServlet的引數配置

通過context-param配置的contextConfigLocation配置到了ServletContext中,再通過Servlet下的init-param配置的contextConfigLocation配置到ServletConfig中,在Servlet中可以通過getInitParameter方法獲取具體的資訊。

3.GenericServlet

GenericServlet是Servlet的預設實現,程式碼如下:


package javax.servlet;
import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.ResourceBundle;
public abstract class GenericServlet
  implements Servlet, ServletConfig, Serializable
{
  private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
  private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.LocalStrings");
  private transient ServletConfig config;
  public void destroy()
  {
  }
  public String getInitParameter(String name)
  {
    ServletConfig sc = getServletConfig();
    if (sc == null) {
      throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
    }
    return sc.getInitParameter(name);
  }
  public Enumeration getInitParameterNames()
  {
    ServletConfig sc = getServletConfig();
    if (sc == null) {
      throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
    }
    return sc.getInitParameterNames();
  }
  public ServletConfig getServletConfig()
  {
    return this.config;
  }
  public ServletContext getServletContext()
  {
    ServletConfig sc = getServletConfig();
    if (sc == null) {
      throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
    }
    return sc.getServletContext();
  }
  public String getServletInfo()
  {
    return "";
  }
  public void init(ServletConfig config)
    throws ServletException
  {
    this.config = config;
    init();
  }
  public void init()
    throws ServletException
  {
  }
  public void log(String msg)
  {
    getServletContext().log(getServletName() + ": " + msg);
  }
  public void log(String message, Throwable t)
  {
    getServletContext().log(getServletName() + ": " + message, t);
  }
  public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
    throws ServletException, IOException;
  public String getServletName()
  {
    ServletConfig sc = getServletConfig();
    if (sc == null) {
      throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
    }
    return sc.getServletName();
  }
}複製程式碼

從其繼承和實現關係來看,GenericServlet主要做了3件事:
1.實現了ServletConfig介面,這樣我們就可以直接呼叫ServletConfig裡面的方法;
GenericServlet實現了ServletConfig,可以在需要的時候直接呼叫ServletConfig中的方法,不需要再先獲取ServletConfig物件;比如,獲取ServletContext的時候可以直接呼叫getServletContext,而無需呼叫getServletConfig().getServletContext(),但是實際上,其底層的內部實現還是在內部還是進行了getServletConfig().getServletContext()的呼叫。


2.提供了無參的init方法
GenericServlet實現了Servlet的init(ServletConfig config)方法,在裡面將config設定給了其內部變數config,然後呼叫了無參的init方法;此方法可以在子類中通過覆蓋它來完成初始化工作。

這種方式具有的有點包括以下幾點:
a.config設定為內部屬性,這樣可以在ServletConfig的介面方法中直接呼叫Config的相應方法來執行;
b.我們在寫Serlvet的時候可以不用再關心Config,只需要執行自己的初始化邏輯即可
c.在重寫init方法時,不需要再呼叫super.init(config)。
3.提供了Log方法
GenericServlet提供了2個log方法,一個用於記錄日誌,一個用於記錄異常。其具體的實現是通過傳給ServletConfig的日誌實現的。
GenericServlet是與具體協議無關的。

4.HttpServlet

HttpServlet是基於Http協議實現的Servlet的基類,寫Servlet時直接繼承HttpServlet即可,不需要再重頭實現Servlet介面,SpringMvc中的dispatcherServlet就是HttpServlet的子類。 HttpServlet是與Http協議相關的,HttpServlet處理請求主要是通過重寫父類的service方法來完成具體的請求處理的。在service方法中首先是將ServletRequest和ServletResponse轉換成HttpServletRequest和HttpServletResponse,然後根據請求的不同路由到不同的處理過程中去【處理方法就是我們常見的doXXX的方法。最常見的就是doGet和doPost】

相關文章