前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。
Servlet(Server Applet),全稱Java Servlet。是用Java編寫的服務器端程序。Servlet 是在服務器上運行的小程序。
其主要功能在于交互式地瀏覽和修改數據,生成動態Web內容。
狹義的Servlet是指Java語言實現的一個接口,廣義的Servlet是指任何實現了這個Servlet接口的類,一般情況下,人們將Servlet理解為后者。
Servlet運行于支持Java的應用服務器中。
從原理上講,Servlet可以響應任何類型的請求,但絕大多數情況下Servlet只用來擴展基于HTTP協議的Web服務器。
Servlet 的主要功能在于交互式地瀏覽和修改數據,生成動態 Web 內容。
這個過程為:
- 客戶端發送請求至服務器端;
- 服務器將請求信息發送至 Servlet;
- Servlet 生成響應內容并將其傳給服務器。響應內容動態生成,通常取決于客戶端的請求;
- 服務器將響應返回給客戶端。
生命周期
- 客戶端請求該 Servlet;
- 加載 Servlet 類到內存;
- 實例化并調用init()方法初始化該 Servlet;
- service()(根據請求方法不同調用doGet() 或者 doPost(),此外還有doHead()、doPut()、doTrace()、doDelete()、doOptions());
- destroy()。
加載和實例化 Servlet。這項操作一般是動態執行的。
然而,Server 通常會提供一個管理的選項,用于在 Server 啟動時強制裝載和初始化特定的 Servlet。
Server 創建一個 Servlet的實例,第一個客戶端的請求到達 Server,Server 調用 Servlet 的 init() 方法(可配置為 Server 創建 Servlet 實例時調用,在 web.xml 中 <servlet> 標簽下配置 <load-on-startup> 標簽,配置的值為整型,值越小 Servlet 的啟動優先級越高)
一個客戶端的請求到達 Server,Server 創建一個請求對象,處理客戶端請求,Server 創建一個響應對象,響應客戶端請求。
Server 激活 Servlet 的 service() 方法,傳遞請求和響應對象作為參數,
service() 方法獲得關于請求對象的信息,處理請求,訪問其他資源,獲得需要的信息,
service() 方法使用響應對象的方法,將響應傳回Server,最終到達客戶端。
service()方法可能激活其它方法以處理請求,如 doGet() 或 doPost() 或程序員自己開發的新的方法。
對于更多的客戶端請求,Server 創建新的請求和響應對象,仍然激活此 Servlet 的 service() 方法,將這兩個對象作為參數傳遞給它。
如此重復以上的循環,但無需再次調用 init() 方法。
一般 Servlet 只初始化一次(只有一個對象),當 Server 不再需要 Servlet 時(一般當 Server 關閉時),Server 調用 Servlet 的 destroy() 方法。
工作模式
? 客戶端發送請求至服務器
服務器啟動并調用 Servlet,Servlet 根據客戶端請求生成響應內容并將其傳給服務器
服務器將響應返回客戶端
編程接口
HTTPServlet?使用一個 HTML 表單來發送和接收數據。要創建一個 HTTPServlet,應當擴展?HttpServlet?類,該類是用專門的方法來處理 HTML?表單的 GenericServlet 的一個子類。 HTML 表單是由 <form> 和 </form> 標記定義的。表單中典型地包含輸入字段(如文本輸入字段、復選框、單選按鈕和選擇列表)和用于提交數據的按鈕。當提交信息時,它們還指定服務器應執行哪一個Servlet(或其它的程序)。 HttpServlet 類包含 init()、destroy()、service() 等方法。其中 init() 和 destroy() 方法是繼承的。
(1) init() 方法
在 Servlet 的生命期中,僅執行一次 init() 方法。它是在服務器裝入 Servlet 時執行的。 可以配置服務器,以在啟動服務器或客戶機首次訪問 Servlet 時裝入 Servlet。 無論有多少客戶機訪問 Servlet,都不會重復執行 init() 。
缺省的 init() 方法通常是符合要求的,但也可以用定制 init() 方法來覆蓋它,典型的是管理服務器端資源。 例如,可能編寫一個定制 init() 來只用于一次裝入 GIF 圖像,改進 Servlet 返回 GIF 圖像和含有多個客戶機請求的性能。另一個示例是初始化數據庫連接。缺省的 init() 方法設置了 Servlet 的初始化參數,并用它的 ServletConfig 對象參數來啟動配置, 因此所有覆蓋 init() 方法的 Servlet 應調用 super.init() 以確保仍然執行這些任務。在調用 service() 方法之前,應確保已完成了 init() 方法。
(2) service() 方法
service() 方法是 Servlet 的核心。每當一個客戶請求一個HttpServlet 對象,該對象的service() 方法就要被調用,而且傳遞給這個方法一個"請求"(ServletRequest)對象和一個"響應"(ServletResponse)對象作為參數。 在 HttpServlet 中已存在 service() 方法。缺省的服務功能是調用與 HTTP 請求的方法相應的 do 功能。例如, 如果 HTTP 請求方法為 GET,則缺省情況下就調用 doGet() 。Servlet 應該為 Servlet 支持的 HTTP 方法覆蓋 do 功能。因為 HttpServlet.service() 方法會檢查請求方法是否調用了適當的處理方法,不必要覆蓋 service() 方法。只需覆蓋相應的 do 方法就可以了。
Servlet 的響應可以是下列幾種類型:
一個輸出流,瀏覽器根據它的內容類型(如 text/html)進行解釋。
一個 HTTP 錯誤響應,重定向到另一個 URL、servlet、JSP。
(3) doGet() 方法
當一個客戶通過 HTML?表單發出一個 HTTP GET 請求或直接請求一個 URL 時,doGet() 方法被調用。與 GET 請求相關的參數添加到 URL 的后面,并與這個請求一起發送。當不會修改服務器端的數據時,應該使用 doGet() 方法。
(4) doPost() 方法
當一個客戶通過 HTML 表單發出一個 HTTP POST 請求時,doPost() 方法被調用。與 POST 請求相關的參數作為一個單獨的 HTTP 請求從瀏覽器發送到服務器。當需要修改服務器端的數據時,應該使用 doPost() 方法。
(5) destroy() 方法
destroy() 方法僅執行一次,即在服務器停止且卸裝 Servlet 時執行該方法。典型的,將 Servlet 作為服務器進程的一部分來關閉。缺省的 destroy() 方法通常是符合要求的,但也可以覆蓋它,典型的是管理服務器端資源。例如,如果 Servlet 在運行時會累計統計數據,則可以編寫一個 destroy() 方法,該方法用于在未裝入 Servlet 時將統計數字保存在文件中。另一個示例是關閉數據庫連接。
當服務器卸裝 Servlet 時,將在所有 service() 方法調用完成后,或在指定的時間間隔過后調用 destroy() 方法。一個 Servlet 在運行 service() 方法時可能會產生其它的線程,因此請確認在調用 destroy() 方法時,這些線程已終止或完成。
(6) getServletConfig() 方法
getServletConfig() 方法返回一個 ServletConfig 對象,該對象用來返回初始化參數和 ServletContext。ServletContext 接口提供有關 servlet 的環境信息。
(7) getServletInfo() 方法
getServletInfo() 方法是一個可選的方法,它提供有關 servlet 的信息,如作者、版本、版權。
當服務器調用 sevlet 的 service()、doGet() 和 doPost() 這三個方法時,均需要 “請求”和“響應”對象作為參數。“請求”對象提供有關請求的信息,而“響應”對象提供了一個將響應信息返回給瀏覽器的一個通信途徑。
javax.servlet 軟件包中的相關類為 ServletResponse 和 ServletRequest,而 javax.servlet.http?軟件包中的相關類為 HttpServletRequest 和 HttpServletResponse。Servlet 通過這些對象與服務器通信并最終與客戶端通信。Servlet 能通過調用"請求"對象的方法獲知客戶端環境,服務器環境的信息和所有由客戶機提供的信息。Servlet 可以調用“響應”對象的方法發送響應,該響應是準備發回客戶端的。
常見容器
Tomcat, Jetty, resin, Oracle Application server, WebLogic Server, Glassfish, Websphere, JBoss 等等。
提供了 Servlet 功能的服務器,叫做 Servlet 容器。對 web 程序來說,Servlet 容器的作用就相當于桌面程序里操作系統的作用,都是提供一些編程基礎
使用建議
在 Web 應用程序中,一個 Servlet 在一個時刻可能被多個用戶同時訪問。這時 Web 容器將為每個用戶創建一個線程來執行 Servlet。如果 Servlet 不涉及共享資源的問題,不必關心多線程問題。但如果 Servlet 需要共享資源,需要保證 Servlet 是線程安全的。
下面是編寫線程安全的 Servlet 的一些建議:
(1)用方法的局部變量保存請求中的專有數據。對方法中定義的局部變量,進入方法的每個線程都有自己的一份方法變量拷貝。任何線程都不會修改其他線程的局部變量。如果要在不同的請求之間共享數據,應該使用會話來共享這類數據。
(2)只用 Servlet的成員變量來存放那些不會改變的數據。有些數據在 Servlet 生命周期中不發生任何變化,通常是在初始時確定的,這些數據可以使用成員變量保存,如數據庫連接名稱、其他資源的路徑等。
(3)對可能被請求修改的成員變量同步。有時數據成員變量或者環境屬性可能被請求修改。當訪問這些數據時應該對它們同步,以避免多個線程同時修改這些數據。
(4)如果 Servlet 訪問外部資源,那么需要同步訪問這些資源。例如,假設 Servlet 要從文件中讀寫數據。當一個線程讀寫一個文件時,其他線程也可能正在讀寫這個文件。文件訪問本身不是線程安全的,所以必須編寫同步訪問這些資源的代碼。在編寫線程安全的 Servlet 時,下面兩種方法是不應該使用的:
(1)在 Servlet API 中提供了一個 SingleThreadModel 接口,實現這個接口的 Servlet 在被多個客戶請求時一個時刻只有一個線程運行。這個接口已被標記不推薦使用。
(2)對 doGet() 或doPost() 方法同步。如果必須在 Servlet 中使用同步代碼,應盡量在最小的代碼塊范圍上進行同步。同步代碼越小,Servlet 執行得才越好