Servlet
1.1 Servlet整體結構
圖解可以看到SevletConfig和Servlet都是頂層介面類,而GenericServlet實現了這兩個頂層類,然後HttpServlet實現了GenericServlet類,所以要實現一個Servlet直接就可以繼承HttpServlet1.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儲存
- 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
複製程式碼
複製程式碼