新聞中心
Servlet與Servlet容器關(guān)系
Servlet
比較這兩個(gè)的區(qū)別, 就得先搞清楚Servlet 的含義, Servlet (/?s?rvlit/ ) 翻譯成中文就是小型應(yīng)用程序或者小服務(wù)程序, 與之相類似的是Server (/?s??rv?r/), 翻譯過(guò)來(lái)是服務(wù)器的意思, 可見(jiàn)這二者承擔(dān)類似的功能,但是Servlet更輕量。

創(chuàng)新互聯(lián)公司是一家專業(yè)提供奎屯企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站建設(shè)、網(wǎng)站制作、成都h5網(wǎng)站建設(shè)、小程序制作等業(yè)務(wù)。10年已為奎屯眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站制作公司優(yōu)惠進(jìn)行中。
web開(kāi)發(fā)的本質(zhì)就一句話:客戶端和服務(wù)器交換數(shù)據(jù)。于是使用 Java 的 Socket 套接字進(jìn)行編程,去處理客戶端來(lái)的 tcp 請(qǐng)求,經(jīng)過(guò)編解碼處理讀取請(qǐng)求體,獲取請(qǐng)求行,然后找到請(qǐng)求行對(duì)應(yīng)的處理邏輯步入服務(wù)器的處理中,處理完畢把對(duì)應(yīng)的結(jié)果返回給當(dāng)前的 Socket 鏈接,響應(yīng)完畢,關(guān)閉 Socket。
上述過(guò)程中, 建立連接、傳輸數(shù)據(jù)、關(guān)閉連接等過(guò)程是tomcat容器幫你做了這些事情, 而拿到請(qǐng)求行之后去找對(duì)應(yīng)的 url 路由,這一部分是誰(shuí)做的呢?是Servlet ! 簡(jiǎn)單來(lái)說(shuō)Servlet就是一段處理 web 請(qǐng)求的邏輯。
具體來(lái)說(shuō)Servlet具有以下幾個(gè)特點(diǎn):
- Servlet是用Java編寫(xiě)的Server端程序,它與協(xié)議和平臺(tái)無(wú)關(guān)。
- Servlet運(yùn)行于Java-enabled Web Server中。
- Java Servlet可以動(dòng)態(tài)地?cái)U(kuò)展Server的能力,并采用請(qǐng)求-響應(yīng)模式提供Web服務(wù)。
- 最早支持Servlet技術(shù)的是JavaSoft的Java Web Server。
- 此后,一些其它的基于Java的Web Server開(kāi)始支持標(biāo)準(zhǔn)的Servlet API。
- Servlet的主要功能在于交互式地瀏覽和修改數(shù)據(jù),生成動(dòng)態(tài)Web內(nèi)容。
上面六點(diǎn)中,最需要被記住的是Servlet可以動(dòng)態(tài)地?cái)U(kuò)展Server的能力,并采用請(qǐng)求-響應(yīng)模式提供Web服務(wù)。
JDK中的Servlet是一個(gè)接口:
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 是一個(gè)接口, 規(guī)定了請(qǐng)求從容器到達(dá) web 服務(wù)端的規(guī)范,詳細(xì)內(nèi)容在后面的Servlet生命周期中詳細(xì)梳理,這兒簡(jiǎn)單概括三個(gè)重要步驟是:
- init():初始化請(qǐng)求的時(shí)候要做什么。
- service():拿到請(qǐng)求的時(shí)候要做什么。
- destory():處理完請(qǐng)求銷(xiāo)毀的時(shí)候要做什么。
所有實(shí)現(xiàn) Servlet 的實(shí)現(xiàn)方都是在這個(gè)規(guī)范的基礎(chǔ)上進(jìn)行開(kāi)發(fā)。那么 Servlet 中的數(shù)據(jù)是從哪里來(lái)的呢?答案就是 Servlet 容器。容器才是真正與客戶端打交道的那一方。一個(gè)容器中 Servlet 可以有多個(gè), 常見(jiàn)的Servlet容器Tomcat,它監(jiān)聽(tīng)了客戶端的請(qǐng)求端口,根據(jù)請(qǐng)求行信息確定將請(qǐng)求交給哪個(gè)Servlet 處理,找到處理的Servlet之后,調(diào)用該Servlet的 service() 方法,處理完畢將對(duì)應(yīng)的處理結(jié)果包裝成ServletResponse 對(duì)象返回給客戶端。
Servlet容器
現(xiàn)在講講Servlet容器, 前面說(shuō)過(guò)看Servlet只是一個(gè)接口或者說(shuō)是規(guī)范, 那么就勢(shì)必有具體實(shí)現(xiàn), 而Servlet具體實(shí)現(xiàn)或者說(shuō)包裝器是Wrapper, 直接管理Wrapper的容器就是Context, 一個(gè) Context 對(duì)應(yīng)一個(gè) Web 工程, 也就是說(shuō)Context 容器如何運(yùn)行將直接影響 Servlet 的工作。
由圖可以知道, Tomcat底層是Context, Context負(fù)責(zé)管理Servlet包裝類Wrapper。
下面創(chuàng)建一個(gè)實(shí)例對(duì)象并調(diào)用 start 方法就可以很容易啟動(dòng) Tomcat,我們還可以通過(guò)這個(gè)對(duì)象來(lái)增加和修改 Tomcat 的配置參數(shù),如可以動(dòng)態(tài)增加 Context、Servlet 等。我們就選擇 Tomcat7 自帶的 examples Web 工程,并看看它是如何加到這個(gè) Context 容器中的。
//給 Tomcat 增加一個(gè) Web 工程:
Tomcat tomcat = getTomcatInstance();
File appDir = new File(getBuildDirectory(), "webapps/examples");
tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath());
tomcat.start();
ByteChunk res = getUrl("http://localhost:" + getPort() +
"/examples/servlets/servlet/HelloWorldExample");
assertTrue(res.toString().indexOf("Hello World!
") > 0);
上述代碼是創(chuàng)建一個(gè) Tomcat 實(shí)例并新增一個(gè) Web 應(yīng)用,然后啟動(dòng) Tomcat 并調(diào)用其中的一個(gè) HelloWorldExample Servlet,看有沒(méi)有正確返回預(yù)期的數(shù)據(jù)。
//Tomcat 的 addWebapp 方法的代碼如下:
public Context addWebapp(Host host, String url, String path) {
silence(url);
Context ctx = new StandardContext();
ctx.setPath( url );
ctx.setDocBase(path);
if (defaultRealm == null) {
initSimpleAuth();
}
ctx.setRealm(defaultRealm);
ctx.addLifecycleListener(new DefaultWebXmlListener());
ContextConfig ctxCfg = new ContextConfig();
ctx.addLifecycleListener(ctxCfg);
ctxCfg.setDefaultWebXml("org/apache/catalin/startup/NO_DEFAULT_XML");
if (host == null) {
getHost().addChild(ctx);
} else {
host.addChild(ctx);
}
return ctx;
}
添加一個(gè) Web 應(yīng)用時(shí)將會(huì)創(chuàng)建一個(gè) StandardContext 容器,并且給這個(gè) Context 容器設(shè)置必要的參數(shù)(url 代表這個(gè)應(yīng)用在 Tomcat 中的訪問(wèn)路徑; path 代表這個(gè)應(yīng)用實(shí)際的物理路徑) 其中最重要的一個(gè)配置是 ContextConfig,【ContextConfig監(jiān)聽(tīng)器】繼承了 【LifecycleListener 監(jiān)聽(tīng)器接口】,它是在調(diào)用清單 2 時(shí)被加入到 StandardContext 容器中。 當(dāng) Context 容器初始化狀態(tài)設(shè)為 init 時(shí),添加在 Context 容器的 Listener 將會(huì)被調(diào)用?!綜ontextConfig監(jiān)聽(tīng)器】將會(huì)負(fù)責(zé)整個(gè) Web 應(yīng)用配置文件的解析工作。最后將這個(gè) Context 容器加到父容器 Host 中。
Servlet生命周期
Servlet生命周期分為四個(gè)部分: 實(shí)例化==>初始化==>執(zhí)行處理==>銷(xiāo)毀。
實(shí)例化
new , 服務(wù)器第一次被訪問(wèn)時(shí),加載一個(gè)Servlet容器,只會(huì)被加載一次。
初始化
init:創(chuàng)建完Servlet容器后,會(huì)調(diào)用僅執(zhí)行一次的init()初始化方法,用于初始化Servlet對(duì)象,無(wú)論多少臺(tái)客戶端在服務(wù)器運(yùn)行期間訪問(wèn)都不會(huì)再執(zhí)行init()方法。
可以在繼承的GenericServlet這個(gè)抽象類中看到初始化方法:
public void init() throws ServletException {
}而在我們的Servlet類中應(yīng)繼承調(diào)用該方法:
public void init() throws ServletException {
super.init();
}
創(chuàng)建Servlet對(duì)象的時(shí)機(jī):
- Servlet容器啟動(dòng)時(shí):讀取web.xml配置文件中的信息,構(gòu)造指定的Servlet對(duì)象,創(chuàng)建ServletConfig對(duì)象,同時(shí)將ServletConfig對(duì)象作為參數(shù)來(lái)調(diào)用Servlet對(duì)象的init方法。
- 在Servlet容器啟動(dòng)后:客戶首次向Servlet發(fā)出請(qǐng)求,Servlet容器會(huì)判斷內(nèi)存中是否存在指定的Servlet對(duì)象,如果沒(méi)有則創(chuàng)建它,然后根據(jù)客戶的請(qǐng)求創(chuàng)建HttpRequest、HttpResponse對(duì)象,從而調(diào)用Servlet 對(duì)象的service方法。
- Servlet:Servlet容器在啟動(dòng)時(shí)自動(dòng)創(chuàng)建Servlet,這是由在web.xml文件中為Servlet設(shè)置的屬性決定的。從中我們也能看到同一個(gè)類型的Servlet對(duì)象在Servlet容器中以單例的形式存在。
執(zhí)行處理
執(zhí)行處理——service()方法
它是Servlet的核心,負(fù)責(zé)響應(yīng)客戶的請(qǐng)求。每當(dāng)一個(gè)客戶請(qǐng)求一個(gè)HttpServlet對(duì)象,該對(duì)象的Service()方法就要調(diào)用,而且傳遞給這個(gè)方法一個(gè)“請(qǐng)求”(ServletRequest)對(duì)象和一個(gè)“響應(yīng)”(ServletResponse)對(duì)象作為參數(shù)。在HttpServlet中已存在Service()方法。默認(rèn)的服務(wù)功能是調(diào)用與HTTP請(qǐng)求的方法相應(yīng)的do功能。
HttpServlet的抽象類提供了doGet()、doPost()……等方法。對(duì)應(yīng)了request請(qǐng)求的發(fā)送方法,與之相匹配:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}上面是操作性最高的部分。
銷(xiāo)毀
銷(xiāo)毀——destroy:在服務(wù)器關(guān)閉或重啟時(shí),Servlet會(huì)調(diào)用destroy方法來(lái)銷(xiāo)毀,將Servlet容器標(biāo)記為垃圾文件,讓GC做回收處理。我們編寫(xiě)的Servlet是調(diào)用了GenericServlet抽象類的destroy方法:
@Override
public void destroy() {
super.destroy();
}
Servlet工作原理
1、首先簡(jiǎn)單解釋一下Servlet接收和響應(yīng)客戶請(qǐng)求的過(guò)程:
客戶發(fā)送一個(gè)請(qǐng)求,Servlet是調(diào)用service()方法對(duì)請(qǐng)求進(jìn)行響應(yīng),service()方法中對(duì)請(qǐng)求的方式進(jìn)行了匹配。選擇調(diào)用doGet,doPost等這些方法,然后再進(jìn)入對(duì)應(yīng)的方法中調(diào)用邏輯層的方法,實(shí)現(xiàn)對(duì)客戶的響應(yīng)。在Servlet接口和GenericServlet中是沒(méi)有doGet()、doPost()等等這些方法的,HttpServlet中定義了這些方法,但是都是返回error信息,所以,我們每次定義一個(gè)Servlet的時(shí)候,都必須實(shí)現(xiàn)doGet或doPost等這些方法。
2、每一個(gè)自定義的Servlet都必須實(shí)現(xiàn)Servlet的接口,Servlet接口中定義了五個(gè)方法,其中比較重要的三個(gè)方法涉及到Servlet的生命周期,分別是上文提到的init(),service(),destroy()方法。GenericServlet是一個(gè)通用的,不特定于任何協(xié)議的Servlet,它實(shí)現(xiàn)了Servlet接口。而HttpServlet繼承于GenericServlet,因此HttpServlet也實(shí)現(xiàn)了Servlet接口。所以我們定義Servlet的時(shí)候只需要繼承HttpServlet即可。
3、Servlet接口和GenericServlet是不特定于任何協(xié)議的,而HttpServlet是特定于HTTP協(xié)議的類,所以HttpServlet中實(shí)現(xiàn)了service()方法,并將請(qǐng)求ServletRequest、ServletResponse 強(qiáng)轉(zhuǎn)為HttpRequest 和 HttpResponse。
4、另外,Servlet是單例模式,線程是不安全的,因此在service()方法中盡量不要操作全局變量。但實(shí)際上,可以通過(guò)使用session和application來(lái)代替全局變量,只是會(huì)加大服務(wù)器負(fù)載。
Servlet處理請(qǐng)求的過(guò)程
- 客戶端發(fā)送請(qǐng)求給服務(wù)器。
- 容器根據(jù)請(qǐng)求及web.xml判斷對(duì)應(yīng)的Servlet是否存在,如果不存在則返回404。
- 容器根據(jù)請(qǐng)求及web.xml判斷對(duì)應(yīng)的Servlet是否已經(jīng)被實(shí)例化,若是相應(yīng)的Servlet沒(méi)有被實(shí)例化,則容器將會(huì)加載相應(yīng)的Servlet到Java虛擬機(jī)并實(shí)例化。
- 調(diào)用實(shí)例對(duì)象的service()方法,并開(kāi)啟一個(gè)新的線程去執(zhí)行相關(guān)處理。調(diào)用servce方法,判斷是調(diào)用doGet方法還是doPost方法。
- 業(yè)務(wù)完成后響應(yīng)相關(guān)的頁(yè)面發(fā)送給客戶端。
當(dāng)前標(biāo)題:Java網(wǎng)絡(luò)編程基本功之Servlet與Servlet容器
標(biāo)題URL:http://www.5511xx.com/article/cdggged.html


咨詢
建站咨詢
