JavaWeb三大元件之Servlet詳解

Breeze_z發表於2018-10-22

Servlet

1.1 Servlet整體結構

JavaWeb三大元件之Servlet詳解
  圖解可以看到SevletConfig和Servlet都是頂層介面類,而GenericServlet實現了這兩個頂層類,然後HttpServlet實現了GenericServlet類,所以要實現一個Servlet直接就可以繼承HttpServlet

1.2 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();
}
複製程式碼

依次解析這五個方法

  • init()方法接收一個ServletConfig引數,由容器傳入,ServletConfig就是Servlet的配置,在web.xml中定義Servlet時通過init-param標籤配置的引數由ServletConfig儲存

JavaWeb三大元件之Servlet詳解

  • init()方法Servlet建立時執行,且只會被呼叫一次
  • getServletConfig()方法獲取Servlet配置
  • service()處理具體請求
  • getServletInfo()獲取Servlet的相關資訊
  • destroy()銷燬物件,伺服器關閉時執行

總結

init(ServletConfig config)這個引數是ServletConfig型別的
ServletConfig這個介面的方法都可以使用
所以能用這個引用引數下的方法
    getInitParameterNames()獲取init-param標籤下的鍵值對
    getServletName()獲取servlet-name裡自定義的值
    getServletContext()獲取context-param標籤下的東西
複製程式碼

1.3 ServletConfig介面

原始碼如下

public interface ServletConfig {
    //用於獲取Servlet名,web.xml中定義的servlet-name
    public String getServletName();
    //獲取應用本身(非常重要)
    public ServletContext getServletContext();
    //獲取init-param中的配置引數
    public String getInitParameter(String name);
    //獲取配置的所有init-param名字集合
    public Enumeration<String> getInitParameterNames();
}
複製程式碼

ServletConfig介面下可獲取web.xml的引數
首先看下web.xml配置

 <servlet>
    <description></description>
    <servlet-name>Servlet1</servlet-name>
    <servlet-class>com.breeze.servlet.Servlet1</servlet-class>
    <init-param>
    	<param-name>a</param-name>
    	<param-value>96</param-value>
    </init-param>
    <init-param>
    	<param-name>b</param-name>
    	<param-value>97</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>Servlet1</servlet-name>
    <url-pattern>/servlet</url-pattern>
  </servlet-mapping>
複製程式碼

接下來獲取這些引數

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("ServletName-----------------------");
		String name=getServletName();
		System.out.println(name);
		
		System.out.println("第一種方式獲得init-param--------------");
		//通過鍵獲得值
		String initParameter = getInitParameter("a");
		System.out.println(initParameter);
		
		System.out.println("第二種方式獲得init-param---------------");
		Enumeration<String> parameterNames =getInitParameterNames();
		while(parameterNames.hasMoreElements()) {
			String key = parameterNames.nextElement();
			String value = getInitParameter(key);
			System.out.println(key+"----"+value);
		}
	}
複製程式碼

1.4 GenericServlet抽象類

GenericServlet是Servlet的預設實現,與具體協議無關的
GenericServlet主要做了三件事
  1,實現了ServletConfig的介面,可以呼叫ServletConfig裡面的方法,不需要獲取getServletConfig物件。獲取ServletContext可以直接呼叫getServletContext,不用getServletConfig().getServletContext()
  用init()把ServletConfig變成內部變數引用,然後重寫ServletConfig介面的所有方法,用這個變數呼叫

public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
    }
但是我們可以看到追根溯源getServletContext()還是由getServletConfig()呼叫的


public ServletConfig getServletConfig() {
        return config;
    }
getServletConfig()方法返回了config,config是從init()方法拿到的ServletConfig
複製程式碼

  2,提供了無參init()方法,

public void init() throws ServletException {}

public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
複製程式碼

  3,提供了兩個log()方法,一個記錄日誌,一個記錄異常,其具體實現是通過傳給ServletConfig的日誌實現的

    public void log(String msg) {
        getServletContext().log(getServletName() + ": " + msg);
    }
    
    public void log(String message, Throwable t) {
        getServletContext().log(getServletName() + ": " + message, t);
    }
複製程式碼

GenericServlet原始碼總結

tomcat會執行init()有參方法
init()有參方法
    引數是web.xml,也就是ServletConfig,把ServletConfig這個引數指向內部變數config
    然後呼叫了init()無參方法
init()無參方法是空的,方便你自己實現類去重寫初始化

GenericServlet重寫了介面ServletConfig的所有方法,用config這個內部變數呼叫
所以我們在實現類就不用去關心config,只需要執行自己的邏輯即可
在重寫init()方法時,也不需要呼叫super.init(config)

所以在實現類去呼叫ServletConfig的方法時,可以直接寫介面類的方法即可,因為GenericServlet重寫了
比如用getInitParameterNames()
不需要在實現類去定義ServletConfig,也不用去this.getServletConfig().getInitParameterNames();
可以直接getInitParameterNames()
複製程式碼

1.5 HttpServlet類

  HttpSerVlet是基於Http協議實現的Servlet基類,我們剛開始寫Servlet的時候是實現Servlet介面,後面在寫Servlet的時候直接繼承HttpServlet類就可以了

  HttpServlet處理請求主要是通過重寫父類的service()來完成具體請求的,在第一個service裡是把ServletRequest和ServletResponse強轉成HttpServletRequest和HttpServletResponse,然後呼叫第二個service()方法

  第二個service則根據http不同的請求,呼叫相應的方法處理,如doGet,doPost,所以我們程式碼也可以寫在doGet,doPost裡

在html介面中,要是沒有設定提交的方法,servlet預設以doGet的方法進行處理。


執行流程

客戶端傳送請求,通過web.xml的url匹配跳轉到到實現類servlet
而實現類繼承HttpServlet,所以先說父類
HttpServlet執行service接受請求進行強轉,呼叫第二個service判斷時什麼方式請求
如判斷的時doGet請求,則執行doGet方法
但我們重寫了doGet方法,所以將請求傳送到了我們重寫的doGet方法中
如果我們重寫的不是doGet而是service則一樣,因覆蓋了父類的service則將請求傳送到我們重寫的sercvice
複製程式碼
複製程式碼

相關文章