Servlet詳解

一、簡介

Servlet是server+Applet的縮寫,表示一個服務器應用。Servlet就是一套規範,按照這套規範寫的代碼就可以直接在Java服務器上面運行。

二、Servlet接口

Servlet是一套規範,那麼在Java中規範則是接口。

2.1 Servlet3.1中Servlet的接口定義如下

public interface Servlet {
    public void init(ServletConfig config) throws ServletException;
    public ServletConfig getServletConfig();    
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;	
    public String getServletInfo();    
    public void destroy();
}

Servlet接口介紹

web.xml配置

    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.lbx.servlet.HelloServlet</servlet-class>
        <init-param>
            <param-name>initParam</param-name>
            <param-value>initValue</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

1 public void init(ServletConfig config) throws ServletException;

 <load-on-startup>值</load-on-startup> 

  1. init()方法初始化內容,被調用時,web容器會把config依賴傳進去。
  2. load-on-startup的值不爲負數時,web容器啓動時會調用init方法。
  3. 沒有填寫load-on-startup標籤或者標籤裏面的值是負數的話,訪問該Servlet的時候會纔會調用init方法。
  4. 同一個Servlet的init方法在整個流程中只會調用一次

2  public  ServletConfig getServletConfig();  

        getServletConfig()方法用來獲取Servlet的配置,比如上面 <init-param>標籤裏面的參數。下面會詳細介紹這個方法。

3 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; 

        service方法用於處於請求,web容器會解析HTTP協議,封裝成對象傳進去。

4  public String getServletInfo();  

        getServletInfo()獲取servlet相關的信息,如作者、版權等,這個方法在需要自己實現,默認返回空字符串。

5 public void destroy();

        destory()方法主要用於Servlet的銷燬,當應用從tomcta移除或者關閉服務器時會被調用,用於釋放資源,只會調用一次。


2.2 ServletConfig接口定義

public interface ServletConfig {
    public String getServletName();
    public ServletContext getServletContext();
    public String getInitParameter(String name);
    public Enumeration<String> getInitParameterNames();
}

ServeltConfig接口介紹

  1. getServeltName():用於獲取Servlet的名字,也就是web.xml中定義的servlet-name。
  2. getServeltContext():獲取ServeltContext對象,全局共享這個對象,一個應用中只能有一個ServletContext對象。可獲取<context-param>裏面內容。
  3. getInitParameter(): 獲取init-param配置的值。
  4. getInitParameterNames():獲取配置的所有Init-param的名字集合。


三、GenericServlet

     GenericServlet這個類實現了Servlet和ServletConfig接口(service()方法用abstract修飾了),可以直接調用Servlet和ServletConfig裏的方法,比如獲取ServletConfig中的方法時候可以直接調用,而無須調用getServletConfig().getServletContext()了,不過底層實現其實是在內部調用了,代碼如下:

    public ServletContext getServletContext() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletContext();
    }

GenericServlet實現了Servlet的init(ServletConfig config)方法,在裏面將config複製給了內部變量config,然後調用無參的init()方法,這個方法是模板方法,在子類中可以通過覆蓋它來完成自己的初始化工作。

public void init(ServletConfig config) throws ServletException {
	this.config = config;
	this.init();
}
public void init() throws ServletException {

}

這種做法有三個作用:

  1. 將參數config設置給內部屬性config,這樣有其他地方需要這個對象就可直接調用。
  2. 做初始化操作時,不用關心config對象。
  3. 重寫init()方法不需要調用super.init(config)。

四、HttpServlet

這個類是我們最常使用的類,繼承了GenericServlet,寫servlet直接繼承就可以了,無需重新實現Servlet接口,這個類主要作用是如何處理請求。

看代碼:

    @Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException
    {
        HttpServletRequest  request;
        HttpServletResponse response;
        
        if (!(req instanceof HttpServletRequest &&
                res instanceof HttpServletResponse)) {
            throw new ServletException("non-HTTP request or response");
        }
        //向下轉型爲HttpServletRequest
        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;
        //調用http的處理方法
        service(request, response);
    }

問題一:爲什麼可以將ServletRequest 強轉爲HttpServletRequest呢?

     因爲在tomcat內部創建的這個request它就是httpServletRequest接口的子類。

問題二:爲什麼要將ServletRequest 強轉爲HttpServletRequest呢?

  1. 因爲ServletRequest中只提供了獲取基本信息的方法。沒有獲取用戶請求類型的方法,而且還包含了許多方法。        

執行完上面方法,最後會調用service方法,調用的不是用一個service,因爲傳入參數類型不一樣,重載方法

這個方法的作用是:獲取Http請求類型,將不同請求類型路由到不同的處理方法。具體方法都是doXXX的結構,doGet,doPost,doPut,doDelete方法都是模板方法,而且如果子類沒有實現將返回404錯誤頁面。


 protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                   
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
           
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }


流程圖


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