這學(xué)期 Java Web 課程的第一節(jié)課就簡短復(fù)習(xí)了一下 Java 的一些基礎(chǔ)知識,所以覺得 Java 的基礎(chǔ)知識還是很重要的,但當(dāng)我想要去寫一篇 Java 回顧的文章的時候發(fā)現(xiàn)很難,因為坑實在太多了(一個頭,兩個大),只能另外找一些時間去寫順便鞏固鞏固自己的基礎(chǔ)。
——【1. 什么是 Servlet 】——
學(xué)習(xí)一個東西就要先去了解它是什么東西。
Servlet 取自兩個單詞:Server、Applet (很符合 sun 公司的命名特點), Java Servlet 的簡稱,其實質(zhì)就是運行在 Web 應(yīng)用服務(wù)器上的 Java 程序,與普通 Java 程序不同,它是位于 Web 服務(wù)器內(nèi)部的服務(wù)器端的 Java 應(yīng)用程序,可以對 Web 瀏覽器或其他 HTTP 客戶端程序發(fā)送的請求進行處理。
狹義的Servlet是指Java語言實現(xiàn)的一個接口,廣義的Servlet是指任何實現(xiàn)了這個Servlet接口的類,一般情況下,人們將Servlet理解為后者。Servlet運行于支持Java的應(yīng)用服務(wù)器中。從原理上講,Servlet可以響應(yīng)任何類型的請求,但絕大多數(shù)情況下Servlet只用來擴展基于HTTP協(xié)議的Web服務(wù)器。
實際上,Servlet 就像是一個規(guī)范,想象一下我們的 USB 接口,它不僅約束了U盤的大小和形狀,同樣也約束了電腦的插槽,Servlet 也是如此,它不僅約束了服務(wù)器端如何實現(xiàn)規(guī)范,也約束著 Java Web 項目的結(jié)構(gòu),為什么這樣說,我們下面再來講,編寫一個 Servlet 其實就是按照 Servlet 規(guī)范編寫一個 Java 類。
——【2. Servlet 與 Servlet 容器 】——
Servlet 對象與普通的 Java 對象不同,它可以處理 Web 瀏覽器或其他 HTTP 客戶端程序發(fā)送的 HTTP 請求,但前提是把 Servlet 對象布置到 Servlet 容器中,也就是說,其運行需要 Servlet 容器的支持。
Servlet 容器也叫做 Servlet 引擎,是 Web 服務(wù)器或應(yīng)用程序服務(wù)器的一部分,用于在發(fā)送的請求和響應(yīng)之上提供網(wǎng)絡(luò)服務(wù),解碼基于 MIME 的請求,格式化基于 MIME 的響應(yīng)。Servlet 沒有 main 方法,不能獨立運行,它必須被部署到 Servlet 容器中,由容器來實例化和調(diào)用 Servlet 的方法(如 doGet() 和 doPost() 方法),Servlet 容器在 Servlet 的生命周期內(nèi)包容和管理 Servlet 。在 JSP 技術(shù) 推出后,管理和運行 Servlet / JSP 的容器也稱為 Web 容器。
有了 Servlet 之后,用戶通過單擊某個鏈接或者直接在瀏覽器的地址欄中輸入 URL 來訪問 Servlet ,Web 服務(wù)器接收到該請求后,并不是將請求直接交給 Servlet ,而是交給 Servlet 容器。Servlet 容器實例化 Servlet ,調(diào)用 Servlet 的一個特定方法對請求進行處理, 并產(chǎn)生一個響應(yīng)。這個響應(yīng)由 Servlet 容器返回給 Web 服務(wù)器,Web 服務(wù)器包裝這個響應(yīng),以 HTTP 響應(yīng)的形式發(fā)送給 Web 瀏覽器。
Servlet 容器能提供什么?
上面我們知道了需要由 Servlet 容器來管理和運行 Servlet ,但是為什么要這樣做呢?使用 Servlet 容器的原因有:
- 通信支持:利用容器提供的方法,你能輕松的讓 Servlet 與 web 服務(wù)器對話,而不用自己建立 serversocket 、監(jiān)聽某個端口、創(chuàng)建流等。容器知道自己與 web 服務(wù)器之間的協(xié)議,所以你的 Servlet 不用擔(dān)心 web 服務(wù)器(如Apache)和你自己的 web 代碼之間的 API ,只需要考慮如何在 Servlet 中實現(xiàn)業(yè)務(wù)邏輯(如處理一個訂單)。
- 生命周期管理: Servlet 容器控制著 Servlet 的生與死,它負(fù)責(zé)加載類、實例化和初始化 Servlet ,調(diào)用 Servlet 方法,以及使 Servlet 實例被垃圾回收,有了 Servlet 容器,你不需要太多的考慮資源管理。
- 多線程支持:容器會自動為它所接收的每個 Servlet 請求創(chuàng)建一個新的 java 線程。針對用戶的請求,如果 Servlet 已經(jīng)運行完相應(yīng)的http服務(wù)方法,這個線程就會結(jié)束。這并不是說你不需要考慮線程安全性,其實你還會遇到同步問題,不過這樣能使你少做很多工作。
- 聲明方式實現(xiàn)安全:利用 Servlet 容器,你可以使用 xml 部署描述文件來配置和修改安全性,而不必將其硬編碼寫到 Servlet 類代碼中。
- JSP支持: Servlet容器負(fù)責(zé)將 jsp 代碼翻譯為真正的 java 代碼。
Servlet 生命周期
通常情況下,Servlet 容器也就是指 Web 容器,如 Tomcat、Jboss、Resin、Weblogic 等,它們對 Servlet 進行控制。當(dāng)一個客戶端發(fā)送 HTTP 請求時,由容器加載 Servlet 對其進行處理并做出響應(yīng)。在 Web 容器中,Servlet 主要經(jīng)歷 4 個階段,如下圖:
Servlet 與 Web 容器的關(guān)系是非常密切的,在 Web 容器中 Servlet 主要經(jīng)歷了 4 個階段,這 4 個階段實質(zhì)是 Servlet 的生命周期,由容器進行管理。
(1)在 Web 容器啟動或者客戶機第一次請求服務(wù)時,容器將加載 Servlet 類并將其放入到 Servlet 實例池。
(2)當(dāng) Servlet 實例化后,容器將調(diào)用 Servlet 對象的 init() 方法完成 Servlet 的初始化操作,主要是為了讓 Servlet 在處理請求之前做一些初始化工作。
(3)容器通過 Servlet 的 service() 方法處理客戶端請求。在 Service() 方法中,Servlet 實例根據(jù)不同的 HTTP 請求類型作出不同處理,并在處理之后作出相應(yīng)的響應(yīng)。
(4)在 Web 容器關(guān)閉時,容器調(diào)用 Servlet 對象的 destroy() 方法對資源進行釋放。在調(diào)用此方法后,Servlet 對象將被垃圾回收器回收。
——【3. 第一個 Servlet 】——
① 搭建 Java Web 項目
- 創(chuàng)建 一個 Java 項目,并命名為 HelloServlet; (注意:這是普通的 Java 項目而不是動態(tài) Web 項目)
- 在項目的根目錄下創(chuàng)建一個文件夾 webapp,表示 Web 項目的根;
- 在 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)前項目的 classpath 路徑改成 webapp/WEB-INF 下的 classes 中。
② 編寫 Servlet
- 為該項目增加Servlet的支持.
1.1. 把Tomcat根/lib中servlet-api.jar文件拷貝到項目下WEB-INF下的lib中
1.2. 在項目中選擇servlet-api.jar,鼠標(biāo)右鍵,build path-->add to build path
- 開發(fā)Servlet程序:
2.1:定義一個類HelloServlet,并讓該類去實現(xiàn)javax.servlet.Servlet接口;
2.2:實現(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("測試一下!"); // 先在這里寫下測試代碼
}
@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 類僅僅是一個普通的實現(xiàn)類而已,而現(xiàn)在我想要它運行在我自己的 Tomcat 服務(wù)器中,所以應(yīng)該通知 Tomcat 服務(wù)器來管理我的 HelloServlet 類,具體的做法如下:
找到項目根下的WEB-INF下的web.xml文件:
在根元素web-app中創(chuàng)建一個新的元素節(jié)點:servlet
-
在根元素web-app中創(chuàng)建一個新的元素節(jié)點: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這個路徑,映射到 HelloServlet 這個類上,需要注意的是:< servlet> 標(biāo)簽下的 < servlet-name>與 < servlet-mapping> 標(biāo)簽下的 < servlet-name> 必須一樣(因為標(biāo)簽被編輯器識別故<后加了一個空格)
-
配置 Tomcat 服務(wù)器:
4.1. 修改默認(rèn)端口為 80 端口:
首先進入到 Tomcat 服務(wù)器的根路徑下找到 conf 文件夾下的 server.xml 文件,默認(rèn)是在第 70 行,找到 Connector 元素的 port 屬性,修改為 80 ,重啟 Tomcat 即可。
Tomcat 的默認(rèn)端口為8080,而 HTTP 協(xié)議的默認(rèn)端口是 80,配置 80 端口的好處在于,我們平時輸入的類似于 http://baidu.com 其實是默認(rèn)省略了寫 80端口的,它其實等價于:http://baidu.com:80/ ,所以以后我們就不用再寫冒號直接輸入 locahost 就能進入到 Tomcat 的配置頁面了。
4.2 部署 Java 項目(告訴 Tomcat 服務(wù)器來管理我們的項目):
這里直接引用 how2j.cn 的教程啦:
所以加上<Context path="" docBase="F:\\Projects\\JavaProject\\HelloServlet\\webapp" />
這一句重啟 Tomcat 服務(wù)器
在瀏覽器中輸入 localhost/hello,回車,即可在 Tomcat 服務(wù)器上看到相關(guān)信息,至此第一個 Servlet 就編寫成功了
——【4. Servlet 請求過程】——
學(xué)習(xí) Servlet 技術(shù),就需要有一個 Servlet 運行環(huán)境,也就是需要有一個 Servlet 容器,如這里使用的【Tomcat】。
Tomcat 服務(wù)器接受客戶請求并做出響應(yīng)的過程如下(以上面搭建的項目為例):
① 打開瀏覽器發(fā)起請求:http://localhost:80/hello/index.html (假設(shè)有一個 index.html 文件)
② 服務(wù)器接收到請求后處理請求:
htpp:所使用的協(xié)議
localhost:ip地址,確定訪問的主機
80:端口號
hello:上下文路徑,確定訪問項目的根路徑
index.html:確定訪問項目中的具體哪一個資源
③ 根據(jù) hello 去 tomcat/conf/server.xml 文件中找到相關(guān)配置文件,根據(jù)上下文路徑找到項目的根路徑:
<Context path="" docBase="F:\\Projects\\JavaProject\\HelloServlet\\webapp" />
如果找不到根路徑(因為這里默認(rèn)上下文路徑為空),返回 404
④ 根據(jù)資源名稱去項目中的 web.xml 文件中找到相關(guān)的配置,找到配置中的<url-pattern>
如果找不到 hello 的資源名稱,則返回 404
⑤ 根據(jù)資源名稱找到 Servlet 的全限定名,如果找不到則在啟動服務(wù)器的時候報錯
java.lang.IllegalArgumentException: Servlet mapping specifies an unknown servlet name HelloServlet
⑥ 根據(jù)找到的全限定名創(chuàng)建對象,在創(chuàng)建對象之前需要判斷是否是第一次請求,使用 Tomcat 中使用 Servlet 實例緩存池來實現(xiàn),若是第一次則調(diào)用對象的 init 方法。
⑦ 創(chuàng)建 req,resp 對象,執(zhí)行 service 方法;
⑧ 使用 resp 對象給瀏覽器響應(yīng)信息。
發(fā)現(xiàn)一邊學(xué)一邊寫起來太麻煩了,一方面是因為自己的水平,另一方面是覺得這樣太費時間了,也要開始找實習(xí)了,所以時間有些寶貴,可能這不會作為一個連續(xù)的系列,反而是一些學(xué)習(xí)的分享和感悟,emmm....事實上,Servlet也還有好多東西,包括最新支持注解方式配置等....
參考資料:
《Java Web程序設(shè)計 慕課版——明日科技》
how2j.cn
理解Servlet和Servlet容器、Web服務(wù)器等概念
歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明出處!
簡書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關(guān)注公眾微信號:wmyskxz
分享自己的學(xué)習(xí) & 學(xué)習(xí)資料 & 生活
想要交流的朋友也可以加qq群:3382693