Servlet


servlet概述

Servlet (Server Applet),全稱Java Servlet。是用Java編寫的服務器端程序。其主要功能在於交互式地瀏覽和修改數據,生成動態Web內容。狹義的Servlet是指Java語言實現的一個接口,廣義的Servlet是指任何實現了這個Servlet接口的類,一般情況下,人們將Servlet理解爲後者。

服務器上需要一些程序,如根據用戶輸入訪問數據庫的程序。在Servlet API產生之前,這些通常是使用公共網關接口(Common Gateway Interface,CGI)應用程序完成的。CGI技術用於創建動態web應用程序。CGI技術有許多缺點,如爲每個請求創建單獨的進程、依賴於平臺代碼(C、C++)、內存消耗大和性能低等。

CGI 和 Servlet

>Servlet在處理時間、內存利用率等方面表現更好。因爲servlet使用多線程技術,爲每個請求創建一個新線程。這自然就比爲每個請求創建新進程的CGI技術要快很多,並且節省內存資源。

>Servlet是平臺無關的,使用Servlet開發的web應用程序可以運行在任何標準的web容器中,如Tomcat、JBoss、Glassfish服務器。同樣可以在任何操作系統中,如Windows、Linux、Unix、Solaris、Mac等。

>Servlet是健壯的,因爲servlet容器負責管理servlet的生命週期,我們不需要擔心內存泄漏、安全、垃圾收集等問題。

>Servlet是易維護的,並且學習曲線小。因爲在使用Servlet的時候我們只需要關注業務邏輯就可以了。

Servlet運行於支持Java的應用服務器中。從原理上講,Servlet可以響應任何類型的請求,但絕大多數情況下Servlet只用來擴展基於HTTP協議的Web服務器。

自MVC規範出現後,Servlet的作用被明確爲僅僅作爲控制器使用,不在生成頁面標籤,也不作爲視圖層角色使用。

Servlet 的主要功能在於交互式地瀏覽和修改數據,生成動態 Web 內容。這個過程爲:

① 客戶端發送請求至服務器端;
② 服務器將請求信息發送至 Servlet;
③ Servlet 生成響應內容並將其傳給服務器。響應內容動態生成,通常取決於客戶端的請求;
④服務器將響應返回給客戶端。

一個 Servlet 就是 Java 編程語言中的一個類,它被用來擴展服務器的性能,服務器上駐留着可以通過“請求-響應”編程模型來訪問的應用程序。雖然 Servlet 可以對任何類型的請求產生響應,但通常只用來擴展 Web 服務器的應用程序。

Servlet API

javax.servlet.Servlet是Servlet API的最上層接口。還有一些其他的接口和類是我們在使用servlet的時候需要關注的。在Servlet 3.0規範中,建議使用的註解我們也需要了解。先了解一下Servlet API層次結構。

這裏寫圖片描述

Servlet接口

javax.servlet.Servlet 是Servlet API的最上層接口,Servlet接口定義了一系列servlet的生命週期方法(init、service、destory等)。所有的Servlet類都需要繼承這個接口。

這裏寫圖片描述

該接口中定義了以下方法:

這裏寫圖片描述

public abstract void init(ServletConfig paramServletConfig) throws ServletException- 該方法由servlet容器調用,用於初始化servlet以及servlet配置參數。在init()方法執行之前,servlet是無法處理用戶請求的。在servlet生命週期中該方法只會被調用一次,他會使servlet類不同區別於普通的java對象。我們可以擴展該方法來初始化資源,如數據庫連接、socket連接等。

public abstract ServletConfig getServletConfig() - 該方法返回一個servlet配置對象,其中包含servlet中所有初始化參數和啓動配置。我們可以用這個方法來獲取servlet的初始化參數,這些參數一般被定義在web.xml或servlet 3的註解中。後面會介紹ServletConfig接口。

public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException- 該方法負責處理客戶端請求。當servlet容器收到客戶端請求時,它會創建一個新線程並執行service()方法,並把request 和 response作爲參數傳遞給該方法。servlet通常運行在多線程環境中,所以開發人員應該使用同步來保證訪問共享資源的線程安全性問題。

public abstract String getServletInfo() - 這個方法返回包含servlet信息的字符串,比如它的作者、版本和版權。返回的字符串應該是純文本,不能有標記符號。

public abstract void destroy() - 這個方法在整個servlet生命週期中只會被調用一次來關閉所有資源。有點像Java中的finalize方法。

GenericServlet抽象類

GenericServlet抽象類實現了Servlet接口、ServletConfig接口和Serializable接口。GenericServlet使得開發人員更加容易地編寫自定義servlets,它提供了生命週期的init()和destroy()方法以及ServletConfig接口的方法的“簡易版本”,該類中定義的大部分方法都是讓用戶更放方便的使用Servlet和ServletConfig接口中定義的常用方法。開發者自定義的servlet只要繼承該抽象類,然後重寫service()方法即可。

這裏寫圖片描述

GenericServlet裏主要實現了Servlet接口、ServletConfig接口的方法,還實現了log()方法,該方法在ServletContext接口裏聲明。

這裏寫圖片描述

GenericServlet裏還有一個重要的方法——無參數的init方法。如果我們必須在處理請求之前初始化一些資源,那麼可以重寫該方法。

HTTPServlet抽象類

HTTPServlet 類是GenericServlet類的子類,開發者通過開發自定類繼承該抽象類,來創建基於HTTP的web應用程序。繼承HTTPServlet抽象類的子類至少要重寫一個HTTPServlet抽象類裏的方法。

這裏寫圖片描述

HTTPServlet抽象類裏的結構。

這裏寫圖片描述

通常客戶端的請求主要有GET和POST請求,自定義Servlet類爲了響應這兩種請求,必須重寫doGet()和doPost()方法,默認調用doGet方法。get方法會在地址欄中顯示用戶名和密碼,post方法不會,在安全性上get小於post;提交內容的大小上get小於post,get提交的數據小於2k,post提交的數據理論上不受限制,實際應用中一般不大於64k;響應速度上get要快於post,get要求服務器立即處理請求,而post請求可能形成一個隊列請求。

如果自定義Servlet類爲了響應4種方式的請求,則需要重寫上面的4個方法。
一般情況下,自定義Servlet類對應所有請求的響應都是一樣的。這樣可以重寫一個方法來代替上面的幾個方法,即只要重寫service()方法及可響應客戶端的所用請求。

- init(ServletConfig config): 創建Servlet實例時,調用該方法初始化Servlet資源;

- destroy(): 消耗Servlet實例時,自動調用該方法的回收資源。

通常這兩個方法不需要重寫,除了要在初始化Servlet時,完成某些資源初始化的方法,才考慮重寫init()方法。如果要在銷燬Servlet之前,先完成某些資源的回收,比如數據庫連接等,才需要重寫destroy()方法。

不用爲自定義Servlet類寫構造器,如果需要初始化該自定義Servlet類,應將初始化操作放在自定義Servlet類的init()方法中定義。如果重寫了init(ServletConfig config)方法,則應在重寫該方法的第一行調用super.init(config),該方法將調用HttpServlet的init方法。

ServletConfig 接口

當一個servlet初始化期間servlet容器會通過servlet配置對象傳遞信息給該servlet。

這裏寫圖片描述

ServletConfig用於描述servlet本身的相關配置信息。每個servlet都有屬於它自己的ServletConfig對象,該對象由servlet容器負責實例化。可以在web.xml中提供初始化參數,當然在servlet3.0中可以使用註解。我們可以使用getServletConfig()方法來獲取ServletConfig的對象。看該接口裏的結構。

這裏寫圖片描述

ServletContext 接口

ServletContext接口用於描述應用程序的相關信息。ServletContext是一個獨立的對象,可用於web應用程序中所有的servlet。當我們想要一些初始化的參數可用於web應用程序中多個或全部servlet時,我們可以使用ServletContext對象並且在web.xml中使用標籤定義參數。我們可以通過ServletConfig 中的 getServletContext()方法得到ServletContext對象。

這裏寫圖片描述

接口結構。

這裏寫圖片描述這裏寫圖片描述


使用Servlet示例

package com.afy.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FirstServletDemo extends HttpServlet {

    @Override
    public void init() throws ServletException {
        System.out.println("=========init without parameters=======");
        super.init();
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("=========init with parameters=======");
        super.init(config);
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("========= service =======");
        PrintWriter pw = response .getWriter();
        pw.println("Hi there,would you wanna play a game?");
        pw.close();
    }

    @Override
    public void destroy() {
        System.out.println("=========destroy=======");
        super.destroy();
    }   

}

FirstServletDemo類繼承了HttpServlet類,表明它可以作爲Servlet使用。其中定義了service方法來響應用戶請求,通過HttpServletRequest獲取客戶端的form請求參數與,並顯示請求參數的值。
Servlet與JSP相比:

  • Servlet中沒有內置對象,原理JSP中的內置對象都必須有程序顯式創建;
  • 對應靜態的HTML標籤,Servlet都必須使用頁面輸出流逐行輸出。

JSP是Servlet的簡化,使用JSP只需程序員輸出到客戶端的內容,至於JSP腳本如何嵌入一個類中,則有JSP容器完成。而Servlet是個完整的Java類,這個類的service()方法用於生成對客戶端的響應。
普通Servlet類裏的service方法的作用等同於JSP生成Servlet類的_jspServlet()方法。

Servlet的配置

寫好的Servlet源文件不能響應用戶的請求,必須將其編譯成class文件。一般.class文件放在WEB-INF/classes路徑下

要Servlet響應用戶請求,必須將Servlet配置在Web應用中。配置Servlet一般是在web.xml文件中操作的。
Servlet3.0開始,配置Servlet有兩種方式

  • 在Servlet類中使用@WebServlet註解進行配置
 @WebServlet(name="FirstServletDemo",urlPattern={"/Hi"})
  • 通過web.xml文件配置

這裏寫圖片描述

因此,配置一個響應客戶請求的Servlet,至少需要配置兩個元素:Servlet的名字和Servlet的URL。

以上示例中,如果在web.xml中配置了Servlet的名字和URL,則該Servlet的URL爲/Hello,如果沒有配置web.xml文件,則該Servlet類上的@WebServlet註解就會起作用,該Servlet的URL爲/Hi。

JSP/Servlet的生命週期

JSP本質就是Servlet,寫好的JSP頁面將由Web容器編譯成對應的Servlet,當Servlet在容器中運行時,其實例的創建和銷燬等都不是由程序員決定的,而是由Web容器進行控制的。
創建Servlet實例有兩種情況
- 客戶端第一次請求某個Servlet時,系統創建Servlet的實例:大部分的Servlet是這種情況創建的;
- Web應用啓動時立即創建Servlet實例,即load-on-startup Servlet。


每個Servlet的運行都遵循如下生命週期

1. 創建Servlet實例;
2. Web容器調用Servlet的init方法,對Servlet進行初始化;
3. Servlet初始化後,將一直存在容器中,用於響應客戶端請求。如果客戶端發送Get請求,容器調用Servlet的doGet方法處理並響應請求;如果客戶端發送Post請求,容器調用Servlet的doPost方法處理並響應請求。或者統一使用service()方法處理響應用戶請求。
4. Web容器決定銷燬Servlet時,先調用Servlet的destroy方法,通常在關閉Web應用之時銷燬Servlet。

這裏寫圖片描述


load-on-startup Servlet

我們已經知道創建Servlet實例有兩個時機:用戶請求時應用啓動時。應用啓動時就創建Servlet,通常用於某些後臺服務的Servlet,或者需要攔截很多請求的Servlet;這種Servlet通常作爲應用的基礎Servlet使用,提供重要的後臺服務。配置load-on-startup的Servlet有兩種方式。

  • 在web.xml文件中通過< servlet…/>元素的< load-on-startup…/>子元素進行配置;
  • 通過@WebServlet註解的loadOnStartup屬性指定。

< load-on-startup…/>元素或loadOnStartup屬性都只接收一個整型值,這個整型值越小,Servlet就越優先優化實例化。
代碼示例

@WebServlet(loadOnStartup=1)
public class TimerServlet extends HttpServlet{
    public void init(ServletConfig config)throws ServletException{
    super.init(config);
    Timer t = new Timer(1000,new ActionListener(){
    public void actionPerformed(ActionEvent e){
        System.out.println(new Date());
    }
    });
    t.start();
    }

}


這個Servlet沒有提供service()方法,這表明它不能響應用戶請求,所以無須爲它配置URL映射。該Servlet僅僅執行計數器功能,每隔一段時間會在控制檯打印出當前時間。由於它不能接收用戶請求,所以只能在應用啓動時實例化。
web.xml文件中配置代碼

< servlet>
    <load-on-startup>1</load-on-startup>
< /servlet>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章