
這學(xué)期 Java Web 課程的第一節(jié)課就簡(jiǎn)短復(fù)習(xí)了一下 Java 的一些基礎(chǔ)知識(shí),所以覺得 Java 的基礎(chǔ)知識(shí)還是很重要的,但當(dāng)我想要去寫一篇 Java 回顧的文章的時(shí)候發(fā)現(xiàn)很難,因?yàn)榭訉?shí)在太多了(一個(gè)頭,兩個(gè)大),只能另外找一些時(shí)間去寫順便鞏固鞏固自己的基礎(chǔ)。
——【1. 什么是 Servlet 】——
學(xué)習(xí)一個(gè)東西就要先去了解它是什么東西。
Servlet 取自兩個(gè)單詞:Server、Applet (很符合 sun 公司的命名特點(diǎn)), Java Servlet 的簡(jiǎn)稱,其實(shí)質(zhì)就是運(yùn)行在 Web 應(yīng)用服務(wù)器上的 Java 程序,與普通 Java 程序不同,它是位于 Web 服務(wù)器內(nèi)部的服務(wù)器端的 Java 應(yīng)用程序,可以對(duì) Web 瀏覽器或其他 HTTP 客戶端程序發(fā)送的請(qǐng)求進(jìn)行處理。
狹義的Servlet是指Java語(yǔ)言實(shí)現(xiàn)的一個(gè)接口,廣義的Servlet是指任何實(shí)現(xiàn)了這個(gè)Servlet接口的類,一般情況下,人們將Servlet理解為后者。Servlet運(yùn)行于支持Java的應(yīng)用服務(wù)器中。從原理上講,Servlet可以響應(yīng)任何類型的請(qǐng)求,但絕大多數(shù)情況下Servlet只用來(lái)擴(kuò)展基于HTTP協(xié)議的Web服務(wù)器。
實(shí)際上,Servlet 就像是一個(gè)規(guī)范,想象一下我們的 USB 接口,它不僅約束了U盤的大小和形狀,同樣也約束了電腦的插槽,Servlet 也是如此,它不僅約束了服務(wù)器端如何實(shí)現(xiàn)規(guī)范,也約束著 Java Web 項(xiàng)目的結(jié)構(gòu),為什么這樣說,我們下面再來(lái)講,編寫一個(gè) Servlet 其實(shí)就是按照 Servlet 規(guī)范編寫一個(gè) Java 類。
——【2. Servlet 與 Servlet 容器 】——
Servlet 對(duì)象與普通的 Java 對(duì)象不同,它可以處理 Web 瀏覽器或其他 HTTP 客戶端程序發(fā)送的 HTTP 請(qǐng)求,但前提是把 Servlet 對(duì)象布置到 Servlet 容器中,也就是說,其運(yùn)行需要 Servlet 容器的支持。
Servlet 容器也叫做 Servlet 引擎,是 Web 服務(wù)器或應(yīng)用程序服務(wù)器的一部分,用于在發(fā)送的請(qǐng)求和響應(yīng)之上提供網(wǎng)絡(luò)服務(wù),解碼基于 MIME 的請(qǐng)求,格式化基于 MIME 的響應(yīng)。Servlet 沒有 main 方法,不能獨(dú)立運(yùn)行,它必須被部署到 Servlet 容器中,由容器來(lái)實(shí)例化和調(diào)用 Servlet 的方法(如 doGet() 和 doPost() 方法),Servlet 容器在 Servlet 的生命周期內(nèi)包容和管理 Servlet 。在 JSP 技術(shù) 推出后,管理和運(yùn)行 Servlet / JSP 的容器也稱為 Web 容器。
有了 Servlet 之后,用戶通過單擊某個(gè)鏈接或者直接在瀏覽器的地址欄中輸入 URL 來(lái)訪問 Servlet ,Web 服務(wù)器接收到該請(qǐng)求后,并不是將請(qǐng)求直接交給 Servlet ,而是交給 Servlet 容器。Servlet 容器實(shí)例化 Servlet ,調(diào)用 Servlet 的一個(gè)特定方法對(duì)請(qǐng)求進(jìn)行處理, 并產(chǎn)生一個(gè)響應(yīng)。這個(gè)響應(yīng)由 Servlet 容器返回給 Web 服務(wù)器,Web 服務(wù)器包裝這個(gè)響應(yīng),以 HTTP 響應(yīng)的形式發(fā)送給 Web 瀏覽器。
Servlet 容器能提供什么?
上面我們知道了需要由 Servlet 容器來(lái)管理和運(yùn)行 Servlet ,但是為什么要這樣做呢?使用 Servlet 容器的原因有:
- 通信支持:利用容器提供的方法,你能輕松的讓 Servlet 與 web 服務(wù)器對(duì)話,而不用自己建立 serversocket 、監(jiān)聽某個(gè)端口、創(chuàng)建流等。容器知道自己與 web 服務(wù)器之間的協(xié)議,所以你的 Servlet 不用擔(dān)心 web 服務(wù)器(如Apache)和你自己的 web 代碼之間的 API ,只需要考慮如何在 Servlet 中實(shí)現(xiàn)業(yè)務(wù)邏輯(如處理一個(gè)訂單)。
- 生命周期管理: Servlet 容器控制著 Servlet 的生與死,它負(fù)責(zé)加載類、實(shí)例化和初始化 Servlet ,調(diào)用 Servlet 方法,以及使 Servlet 實(shí)例被垃圾回收,有了 Servlet 容器,你不需要太多的考慮資源管理。
- 多線程支持:容器會(huì)自動(dòng)為它所接收的每個(gè) Servlet 請(qǐng)求創(chuàng)建一個(gè)新的 java 線程。針對(duì)用戶的請(qǐng)求,如果 Servlet 已經(jīng)運(yùn)行完相應(yīng)的http服務(wù)方法,這個(gè)線程就會(huì)結(jié)束。這并不是說你不需要考慮線程安全性,其實(shí)你還會(huì)遇到同步問題,不過這樣能使你少做很多工作。
- 聲明方式實(shí)現(xiàn)安全:利用 Servlet 容器,你可以使用 xml 部署描述文件來(lái)配置和修改安全性,而不必將其硬編碼寫到 Servlet 類代碼中。
- JSP支持: Servlet容器負(fù)責(zé)將 jsp 代碼翻譯為真正的 java 代碼。
Servlet 生命周期
通常情況下,Servlet 容器也就是指 Web 容器,如 Tomcat、Jboss、Resin、Weblogic 等,它們對(duì) Servlet 進(jìn)行控制。當(dāng)一個(gè)客戶端發(fā)送 HTTP 請(qǐng)求時(shí),由容器加載 Servlet 對(duì)其進(jìn)行處理并做出響應(yīng)。在 Web 容器中,Servlet 主要經(jīng)歷 4 個(gè)階段,如下圖:

Servlet 與 Web 容器的關(guān)系是非常密切的,在 Web 容器中 Servlet 主要經(jīng)歷了 4 個(gè)階段,這 4 個(gè)階段實(shí)質(zhì)是 Servlet 的生命周期,由容器進(jìn)行管理。
(1)在 Web 容器啟動(dòng)或者客戶機(jī)第一次請(qǐng)求服務(wù)時(shí),容器將加載 Servlet 類并將其放入到 Servlet 實(shí)例池。
(2)當(dāng) Servlet 實(shí)例化后,容器將調(diào)用 Servlet 對(duì)象的 init() 方法完成 Servlet 的初始化操作,主要是為了讓 Servlet 在處理請(qǐng)求之前做一些初始化工作。
(3)容器通過 Servlet 的 service() 方法處理客戶端請(qǐng)求。在 Service() 方法中,Servlet 實(shí)例根據(jù)不同的 HTTP 請(qǐng)求類型作出不同處理,并在處理之后作出相應(yīng)的響應(yīng)。
(4)在 Web 容器關(guān)閉時(shí),容器調(diào)用 Servlet 對(duì)象的 destroy() 方法對(duì)資源進(jìn)行釋放。在調(diào)用此方法后,Servlet 對(duì)象將被垃圾回收器回收。
——【3. 第一個(gè) Servlet 】——
① 搭建 Java Web 項(xiàng)目
- 創(chuàng)建 一個(gè) Java 項(xiàng)目,并命名為 HelloServlet; (注意:這是普通的 Java 項(xiàng)目而不是動(dòng)態(tài) Web 項(xiàng)目)
- 在項(xiàng)目的根目錄下創(chuàng)建一個(gè)文件夾 webapp,表示 Web 項(xiàng)目的根;
- 在 webapp 中創(chuàng)建 WEB-INF 文件夾;
- 在 WEB-INF 文件夾中創(chuàng)建文件夾:classes,lib;
- 在 WEB-INF 文件中添加 Tomcat 根目錄下 conf 文件夾中的 web.xml 文件;(只保留根元素,就像下面這樣)
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> </web-app> - 把當(dāng)前項(xiàng)目的 classpath 路徑改成 webapp/WEB-INF 下的 classes 中。

② 編寫 Servlet
- 為該項(xiàng)目增加Servlet的支持.
1.1. 把Tomcat根/lib中servlet-api.jar文件拷貝到項(xiàng)目下WEB-INF下的lib中
1.2. 在項(xiàng)目中選擇servlet-api.jar,鼠標(biāo)右鍵,build path-->add to build path

- 開發(fā)Servlet程序:
2.1:定義一個(gè)類HelloServlet,并讓該類去實(shí)現(xiàn)javax.servlet.Servlet接口;
2.2:實(shí)現(xiàn)Servlet接口中的init,service,destory等方法.
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class HelloServlet implements Servlet{
@Override
public void init(ServletConfig config) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("測(cè)試一下!"); // 先在這里寫下測(cè)試代碼
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
注意:若生成方法中的參數(shù)是 arg0 或則 arg1 等格式的,原因是還沒有關(guān)聯(lián)源代碼的問題: 關(guān)聯(lián)上 tomcat src 文件即可
③ 配置 Servlet
上面編寫好的 HelloServlet 類僅僅是一個(gè)普通的實(shí)現(xiàn)類而已,而現(xiàn)在我想要它運(yùn)行在我自己的 Tomcat 服務(wù)器中,所以應(yīng)該通知 Tomcat 服務(wù)器來(lái)管理我的 HelloServlet 類,具體的做法如下:
找到項(xiàng)目根下的WEB-INF下的web.xml文件:
在根元素web-app中創(chuàng)建一個(gè)新的元素節(jié)點(diǎn):servlet
-
在根元素web-app中創(chuàng)建一個(gè)新的元素節(jié)點(diǎn):servlet-mapping(Servlet 的映射)
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>lt.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>web.xml 提供路徑和servlet映射關(guān)系,這意思是把/hello這個(gè)路徑,映射到 HelloServlet 這個(gè)類上,需要注意的是:< servlet> 標(biāo)簽下的 < servlet-name>與 < servlet-mapping> 標(biāo)簽下的 < servlet-name> 必須一樣(因?yàn)闃?biāo)簽被編輯器識(shí)別故<后加了一個(gè)空格)
-
配置 Tomcat 服務(wù)器:
4.1. 修改默認(rèn)端口為 80 端口:
首先進(jìn)入到 Tomcat 服務(wù)器的根路徑下找到 conf 文件夾下的 server.xml 文件,默認(rèn)是在第 70 行,找到 Connector 元素的 port 屬性,修改為 80 ,重啟 Tomcat 即可。
Tomcat 的默認(rèn)端口為8080,而 HTTP 協(xié)議的默認(rèn)端口是 80,配置 80 端口的好處在于,我們平時(shí)輸入的類似于 http://baidu.com 其實(shí)是默認(rèn)省略了寫 80端口的,它其實(shí)等價(jià)于:http://baidu.com:80/ ,所以以后我們就不用再寫冒號(hào)直接輸入 locahost 就能進(jìn)入到 Tomcat 的配置頁(yè)面了。
4.2 部署 Java 項(xiàng)目(告訴 Tomcat 服務(wù)器來(lái)管理我們的項(xiàng)目):
這里直接引用 how2j.cn 的教程啦:
所以加上<Context path="" docBase="F:\\Projects\\JavaProject\\HelloServlet\\webapp" />這一句重啟 Tomcat 服務(wù)器
在瀏覽器中輸入 localhost/hello,回車,即可在 Tomcat 服務(wù)器上看到相關(guān)信息,至此第一個(gè) Servlet 就編寫成功了

——【4. Servlet 請(qǐng)求過程】——
學(xué)習(xí) Servlet 技術(shù),就需要有一個(gè) Servlet 運(yùn)行環(huán)境,也就是需要有一個(gè) Servlet 容器,如這里使用的【Tomcat】。
Tomcat 服務(wù)器接受客戶請(qǐng)求并做出響應(yīng)的過程如下(以上面搭建的項(xiàng)目為例):
① 打開瀏覽器發(fā)起請(qǐng)求:http://localhost:80/hello/index.html (假設(shè)有一個(gè) index.html 文件)
② 服務(wù)器接收到請(qǐng)求后處理請(qǐng)求:
htpp:所使用的協(xié)議
localhost:ip地址,確定訪問的主機(jī)
80:端口號(hào)
hello:上下文路徑,確定訪問項(xiàng)目的根路徑
index.html:確定訪問項(xiàng)目中的具體哪一個(gè)資源
③ 根據(jù) hello 去 tomcat/conf/server.xml 文件中找到相關(guān)配置文件,根據(jù)上下文路徑找到項(xiàng)目的根路徑:
<Context path="" docBase="F:\\Projects\\JavaProject\\HelloServlet\\webapp" />
如果找不到根路徑(因?yàn)檫@里默認(rèn)上下文路徑為空),返回 404
④ 根據(jù)資源名稱去項(xiàng)目中的 web.xml 文件中找到相關(guān)的配置,找到配置中的<url-pattern>

如果找不到 hello 的資源名稱,則返回 404
⑤ 根據(jù)資源名稱找到 Servlet 的全限定名,如果找不到則在啟動(dòng)服務(wù)器的時(shí)候報(bào)錯(cuò)
java.lang.IllegalArgumentException: Servlet mapping specifies an unknown servlet name HelloServlet
⑥ 根據(jù)找到的全限定名創(chuàng)建對(duì)象,在創(chuàng)建對(duì)象之前需要判斷是否是第一次請(qǐng)求,使用 Tomcat 中使用 Servlet 實(shí)例緩存池來(lái)實(shí)現(xiàn),若是第一次則調(diào)用對(duì)象的 init 方法。
⑦ 創(chuàng)建 req,resp 對(duì)象,執(zhí)行 service 方法;
⑧ 使用 resp 對(duì)象給瀏覽器響應(yīng)信息。
發(fā)現(xiàn)一邊學(xué)一邊寫起來(lái)太麻煩了,一方面是因?yàn)樽约旱乃?,另一方面是覺得這樣太費(fèi)時(shí)間了,也要開始找實(shí)習(xí)了,所以時(shí)間有些寶貴,可能這不會(huì)作為一個(gè)連續(xù)的系列,反而是一些學(xué)習(xí)的分享和感悟,emmm....事實(shí)上,Servlet也還有好多東西,包括最新支持注解方式配置等....
參考資料:
《Java Web程序設(shè)計(jì) 慕課版——明日科技》
how2j.cn
理解Servlet和Servlet容器、Web服務(wù)器等概念
歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處!
簡(jiǎn)書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關(guān)注公眾微信號(hào):wmyskxz
分享自己的學(xué)習(xí) & 學(xué)習(xí)資料 & 生活
想要交流的朋友也可以加qq群:3382693

