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