新聞中心
Servlet與Servlet容器關(guān)系
Servlet
比較這兩個(gè)的區(qū)別, 就得先搞清楚Servlet 的含義, Servlet (/?s?rvlit/ ) 翻譯成中文就是小型應(yīng)用程序或者小服務(wù)程序, 與之相類似的是Server (/?s??rv?r/), 翻譯過來是服務(wù)器的意思, 可見這二者承擔(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開發(fā)的本質(zhì)就一句話:客戶端和服務(wù)器交換數(shù)據(jù)。于是使用 Java 的 Socket 套接字進(jìn)行編程,去處理客戶端來的 tcp 請(qǐng)求,經(jīng)過編解碼處理讀取請(qǐng)求體,獲取請(qǐng)求行,然后找到請(qǐng)求行對(duì)應(yīng)的處理邏輯步入服務(wù)器的處理中,處理完畢把對(duì)應(yīng)的結(jié)果返回給當(dāng)前的 Socket 鏈接,響應(yīng)完畢,關(guān)閉 Socket。
上述過程中, 建立連接、傳輸數(shù)據(jù)、關(guān)閉連接等過程是tomcat容器幫你做了這些事情, 而拿到請(qǐng)求行之后去找對(duì)應(yīng)的 url 路由,這一部分是誰(shuí)做的呢?是Servlet ! 簡(jiǎn)單來說Servlet就是一段處理 web 請(qǐng)求的邏輯。
具體來說Servlet具有以下幾個(gè)特點(diǎn):
- Servlet是用Java編寫的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開始支持標(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)求銷毀的時(shí)候要做什么。
所有實(shí)現(xiàn) Servlet 的實(shí)現(xiàn)方都是在這個(gè)規(guī)范的基礎(chǔ)上進(jìn)行開發(fā)。那么 Servlet 中的數(shù)據(jù)是從哪里來的呢?答案就是 Servlet 容器。容器才是真正與客戶端打交道的那一方。一個(gè)容器中 Servlet 可以有多個(gè), 常見的Servlet容器Tomcat,它監(jiān)聽了客戶端的請(qǐng)求端口,根據(jù)請(qǐng)求行信息確定將請(qǐng)求交給哪個(gè)Servlet 處理,找到處理的Servlet之后,調(diào)用該Servlet的 service() 方法,處理完畢將對(duì)應(yīng)的處理結(jié)果包裝成ServletResponse 對(duì)象返回給客戶端。
Servlet容器
現(xiàn)在講講Servlet容器, 前面說過看Servlet只是一個(gè)接口或者說是規(guī)范, 那么就勢(shì)必有具體實(shí)現(xiàn), 而Servlet具體實(shí)現(xiàn)或者說包裝器是Wrapper, 直接管理Wrapper的容器就是Context, 一個(gè) Context 對(duì)應(yīng)一個(gè) Web 工程, 也就是說Context 容器如何運(yùn)行將直接影響 Servlet 的工作。
由圖可以知道, Tomcat底層是Context, Context負(fù)責(zé)管理Servlet包裝類Wrapper。
下面創(chuàng)建一個(gè)實(shí)例對(duì)象并調(diào)用 start 方法就可以很容易啟動(dòng) Tomcat,我們還可以通過這個(gè)對(duì)象來增加和修改 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,看有沒有正確返回預(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 中的訪問路徑; path 代表這個(gè)應(yīng)用實(shí)際的物理路徑) 其中最重要的一個(gè)配置是 ContextConfig,【ContextConfig監(jiān)聽器】繼承了 【LifecycleListener 監(jiān)聽器接口】,它是在調(diào)用清單 2 時(shí)被加入到 StandardContext 容器中。 當(dāng) Context 容器初始化狀態(tài)設(shè)為 init 時(shí),添加在 Context 容器的 Listener 將會(huì)被調(diào)用?!綜ontextConfig監(jiān)聽器】將會(huì)負(fù)責(zé)整個(gè) Web 應(yīng)用配置文件的解析工作。最后將這個(gè) Context 容器加到父容器 Host 中。
Servlet生命周期
Servlet生命周期分為四個(gè)部分: 實(shí)例化==>初始化==>執(zhí)行處理==>銷毀。
實(shí)例化
new , 服務(wù)器第一次被訪問時(shí),加載一個(gè)Servlet容器,只會(huì)被加載一次。
初始化
init:創(chuàng)建完Servlet容器后,會(huì)調(diào)用僅執(zhí)行一次的init()初始化方法,用于初始化Servlet對(duì)象,無(wú)論多少臺(tái)客戶端在服務(wù)器運(yù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ù)來調(diào)用Servlet對(duì)象的init方法。
- 在Servlet容器啟動(dòng)后:客戶首次向Servlet發(fā)出請(qǐng)求,Servlet容器會(huì)判斷內(nèi)存中是否存在指定的Servlet對(duì)象,如果沒有則創(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);
}
}上面是操作性最高的部分。
銷毀
銷毀——destroy:在服務(wù)器關(guān)閉或重啟時(shí),Servlet會(huì)調(diào)用destroy方法來銷毀,將Servlet容器標(biāo)記為垃圾文件,讓GC做回收處理。我們編寫的Servlet是調(diào)用了GenericServlet抽象類的destroy方法:
@Override
public void destroy() {
super.destroy();
}
Servlet工作原理
1、首先簡(jiǎn)單解釋一下Servlet接收和響應(yīng)客戶請(qǐng)求的過程:
客戶發(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中是沒有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í)際上,可以通過使用session和application來代替全局變量,只是會(huì)加大服務(wù)器負(fù)載。
Servlet處理請(qǐng)求的過程
- 客戶端發(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沒有被實(shí)例化,則容器將會(huì)加載相應(yīng)的Servlet到Java虛擬機(jī)并實(shí)例化。
- 調(diào)用實(shí)例對(duì)象的service()方法,并開啟一個(gè)新的線程去執(zhí)行相關(guān)處理。調(diào)用servce方法,判斷是調(diào)用doGet方法還是doPost方法。
- 業(yè)務(wù)完成后響應(yīng)相關(guān)的頁(yè)面發(fā)送給客戶端。
分享文章:Java網(wǎng)絡(luò)編程基本功之Servlet與Servlet容器
分享URL:http://m.fisionsoft.com.cn/article/cdggged.html


咨詢
建站咨詢
