Servlet的核心是Servelt那么我們就以此展開進(jìn)回顧
Servlet接口定義如下:
package javax.servlet;
import java.io.IOException;
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雏搂、Service和destory是生命周期的方法:
(1) init()方法:當(dāng)?shù)谝淮握?qǐng)求Servlet時(shí),創(chuàng)建完servlet對(duì)象的時(shí)候調(diào)用拳氢。只會(huì)調(diào)用1次杭煎。說(shuō)明Servelt是單例哼拔,成員變量有線程安全的問(wèn)題概行。
(2) service()方法:每次發(fā)出請(qǐng)求時(shí)調(diào)用盖呼。調(diào)用n次儒鹿,也就是說(shuō)每發(fā)出一次請(qǐng)求都會(huì)調(diào)用一次service()。
(3) destroy()方法: 銷毀servlet對(duì)象的時(shí)候調(diào)用几晤。停止服務(wù)器或者重新部署web應(yīng)用時(shí)銷毀servlet對(duì)象约炎。只會(huì)調(diào)用1次。
其他兩個(gè)非生命周期的方法:
getServletInfo():獲取Servelt的描述信息
getServletConfig():獲取封裝Servelt配置的ServeltConfig
?由于Servlet不是線程安全的蟹瘾,一個(gè)應(yīng)用程序中所有的用戶公用一個(gè)Servlet實(shí)例圾浅,因此不建議使用類級(jí)別的變量(只使用局部變量最好),除非是只讀的或者java.utilconcurrent.atomic包中的成員憾朴。
其中涉及到的對(duì)象:
ServletRequest :
?對(duì)于每一個(gè)HTTP請(qǐng)求狸捕,servlet容器會(huì)創(chuàng)建一個(gè)封裝了HTTP請(qǐng)求的ServletRequest實(shí)例傳遞給servlet的service方法。
ServletResponse:
?ServletResponse則表示一個(gè)Servlet響應(yīng)众雷,在調(diào)用service方法前灸拍,servelt容器首先創(chuàng)建一個(gè)ServeltResponse,并 將它作為第二個(gè)參數(shù)傳給Service方法砾省。其影藏了將響應(yīng)發(fā)給瀏覽器的復(fù)雜性鸡岗。
ServletConfig:
?ServletConfig封裝可以通過(guò)@WebServlet或者web.xml傳給一個(gè)Servlet的配置信息,以這種方式傳遞的每一條信息都稱做初始化信息编兄,初始化信息就是一個(gè)個(gè)K-V鍵值對(duì)轩性。為了從一個(gè)Servlet內(nèi)部獲取某個(gè)初始參數(shù)的值,init方法中調(diào)用ServletConfig的getinitParameter方法或getinitParameterNames方法獲取狠鸳,除此之外揣苏,還可以通過(guò)getServletContext獲取ServletContext對(duì)象。
ServletContext:
?ServletContext是代表了Servlet應(yīng)用程序碰煌。每個(gè)Web應(yīng)用程序只有一個(gè)context舒岸。在分布式環(huán)境中,一個(gè)應(yīng)用程序同時(shí)部署到多個(gè)容器中芦圾,并且每臺(tái)Java虛擬機(jī)都有一個(gè)ServletContext對(duì)象蛾派。有了ServletContext對(duì)象后,就可以共享能通過(guò)應(yīng)用程序的所有資源訪問(wèn)的信息个少,促進(jìn)Web對(duì)象的動(dòng)態(tài)注冊(cè)洪乍,共享的信息通過(guò)一個(gè)內(nèi)部Map中的對(duì)象保存在ServiceContext中來(lái)實(shí)現(xiàn)。保存在ServletContext中的對(duì)象稱作屬性夜焦。
接著我們來(lái)看看Servlet的兩個(gè)子類:
GenericServlet:
GenericServlet抽象類就是為了為我們省略一些模板代碼壳澳,實(shí)現(xiàn)了Servlet和ServletConfig,完成了一下幾個(gè)工作:
1茫经、將init方法中的ServletConfig賦給一個(gè)類級(jí)變量巷波,使的可以通過(guò)getServletConfig來(lái)獲取萎津。
2、為Servlet接口中的所有方法提供默認(rèn)實(shí)現(xiàn)抹镊。
3锉屈、提供方法來(lái)包裝ServletConfig中的方法。
HttpServelt
?HttpServlet繼承了GenericServlet垮耳,HttpServletRequest/Response繼承了覆蓋了ServletRequest/Response颈渊,成為了新的Servlet請(qǐng)求和響應(yīng)的代表。在HttpServlet中覆蓋了GenericServlet的service方法终佛,并用新的Servlet請(qǐng)求和響應(yīng)代表作為參數(shù)添加了一個(gè)service方法:
//覆蓋GenereicServlet中的service
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");
}
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
service(request, response);
}
}
?原始的service方法將請(qǐng)求和響應(yīng)進(jìn)行向下轉(zhuǎn)換俊嗽,分別為HttpServletRequest和HttpServletResponse,HttpServletRequest,HttpServletResponse由于帶有了HTTP的特性铃彰,因此除了ServletRequest绍豁,ServletResponse中的方法之外還增加了幾個(gè)可以獲取HTTP特性信息的方法。
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) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
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 {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
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);
}
}
Service方法會(huì)通過(guò)httpServeltRequest.getMethod()檢查用來(lái)發(fā)送http請(qǐng)求的方法并調(diào)用doGet豌研、doPut妹田、doPost、doDelete鹃共、doHead鬼佣、doTrace、doOptions這7種方法霜浴。這7種方法每一種都代表著一個(gè)http方法晶衷。
HTTP請(qǐng)求的方法:
HTTP/1.1協(xié)議中共定義了八種方法(有時(shí)也叫“動(dòng)作”),來(lái)表明Request-URL指定的資源不同的操作方式
1阴孟、GET:請(qǐng)求指定的頁(yè)面信息晌纫,并返回實(shí)體主體。
2永丝、HEAD:類似于get請(qǐng)求锹漱,只不過(guò)返回的響應(yīng)中沒(méi)有響應(yīng)體,用于獲取消息頭中的元信息
3慕嚷、POST:向指定資源提交數(shù)據(jù)進(jìn)行處理請(qǐng)求(例如提交表單或者上傳文件)哥牍。數(shù)據(jù)被包含在請(qǐng)求體中。POST請(qǐng)求可能會(huì)導(dǎo)致新的資源的建立和/或已有資源的修改喝检。
4嗅辣、PUT:向指定資源位置上傳其最新內(nèi)容。
5挠说、DELETE:請(qǐng)求服務(wù)器刪除Request-URL所標(biāo)識(shí)的資源澡谭。
6、CONNECT:HTTP/1.1協(xié)議中預(yù)留給能夠?qū)⑦B接改為管道方式的代理服務(wù)器损俭。
7蛙奖、OPTIONS:返回服務(wù)器針對(duì)特定資源所支持的HTTP請(qǐng)求方法潘酗,也可以利用向web服務(wù)器發(fā)送‘*’的請(qǐng)求來(lái)測(cè)試服務(wù)器的功能性
8、TRACE:回顯服務(wù)器收到的請(qǐng)求外永,主要用于測(cè)試或診斷崎脉。