Java Web-Servlet

章節(jié)目錄

  • 什么是Servlet
  • Servlet 烘嘱、ServletContext赚导、Servlet Container被因、web 容器之間的區(qū)別
  • Servlet卿拴、ServletConfig、GenericServlet梨与、HttpServlet堕花、自定義Servlet 之間的聯(lián)系
  • HttpServlet 源碼解析
  • Servlet 是否是線程安全的-線程非安全

1.什么是Servlet

1.1 定義
首先看Servlet接口源碼中對(duì)于Servlet的定義

A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP, the
HyperText Transfer Protocol.

譯文如下:

Servlet 是運(yùn)行在Web服務(wù)器上的小型Java程序,Servlet 接受并響應(yīng)來(lái)自Web 客戶端的請(qǐng)求粥鞋,通常請(qǐng)求通過(guò)HTTP協(xié)議進(jìn)行請(qǐng)求傳輸缘挽。

總結(jié)如下:

1.Java Servlet 運(yùn)行在 Web 服務(wù)器(Web 容器)之上,即1個(gè)Web服務(wù)器上可部署運(yùn)行多個(gè)Servlet呻粹。
2.Servlet 的功能是-接收來(lái)自客戶端發(fā)送的 HTTP 請(qǐng)求壕曼,并在接收 HTTP 請(qǐng)求
之后做相關(guān)處理,處理完成之后將數(shù)據(jù)響應(yīng)給客戶端等浊。

2. Servlet 腮郊、ServletContext、Servlet Container凿掂、web 容器之間的區(qū)別

2.1 servlet

servlet 用來(lái)接收伴榔、處理請(qǐng)求纹蝴,并返回?cái)?shù)據(jù)。

2.2 ServletContext

ServletContext (Servlet上下文對(duì)象)是web應(yīng)用服務(wù)器啟動(dòng)之后創(chuàng)建的對(duì)象踪少,且只在web應(yīng)用服務(wù)器啟動(dòng)時(shí)創(chuàng)建一次塘安,所有的Servlet 可以共享并修改在ServletContext設(shè)置的共享變量。

源碼注釋如下所示

Defines a set of methods that a servlet uses to communicate with its servlet
container, for example, to get the MIME type of a file, dispatch requests, or
write to a log file.

譯文如下:

ServletContext 中定義了讓單獨(dú)的Servlet與Servlet容器進(jìn)行交互的一系列操作方法援奢,如獲取文件的 MIME type兼犯,如text/htmimage/gif集漾,getRequestDispatcher操作(重定向操作)301-永久重定向 對(duì)應(yīng) forward()切黔、302-臨時(shí)重定向對(duì)應(yīng)redirect()、或者寫(xiě)日志文件操作具篇。

2.3.Servlet Contanier

Servlet 容器纬霞,可以在其之上搭載多個(gè)Servlet,類(lèi)似于Servlet是子彈驱显、Servlet 容器是槍诗芜。

2.4.web 容器

web 容器 即 web服務(wù)器,Servlet 容器搭載于Web 容器之上埃疫,請(qǐng)求過(guò)來(lái)之后伏恐,
先到達(dá)至web服務(wù)器,web服務(wù)器將請(qǐng)求傳遞至Servlet容器栓霜,Servlet容器根據(jù)
一定的匹配規(guī)則翠桦,如Servlet-Mapping 將 請(qǐng)求傳遞至對(duì)應(yīng)的Servlet處理程序,
這便是請(qǐng)求的部分傳遞過(guò)程胳蛮。即 request->web container->servlet container->servlet销凑。

3.Servlet、ServletConfig仅炊、GenericServlet闻鉴、HttpServlet、自定義Servlet 之間的聯(lián)系

3.1 相關(guān)類(lèi)圖

Servlet 類(lèi)圖關(guān)系

接下來(lái)茂洒,各個(gè)擊破:
3.2 Servlet 接口
如下圖所示Servlet 接口中聲明的public 方法:
Servlet 接口聲明的方法

Servlet 中定義了5個(gè)方法:

init(ServletConfig):Servlet在容器啟動(dòng)時(shí)不進(jìn)行實(shí)例化所以不調(diào)用init()方法,
只有當(dāng)?shù)谝粋€(gè)請(qǐng)求通過(guò)Servlet 中 Service()方法進(jìn)行處理時(shí)才進(jìn)行實(shí)例化瓶竭,且只實(shí)例化一次督勺,該方法被Servlet Container 調(diào)用。

getServletConfig():獲取與當(dāng)前Servlet 綁定的 ServletConfig 對(duì)象斤贰,
ServletConfig 對(duì)象包含 web.xml 配置文件中配置的 ServletName智哀、
initParameter等信息。通過(guò)ServletConfig 對(duì)象可以獲取到ServletContext對(duì)
象荧恍,所以ServletConfig 對(duì)象是 不同 Servlet 之間共享Servlet 容器信息 的橋
梁瓷叫。

service():接受客戶端請(qǐng)求對(duì)象屯吊、執(zhí)行業(yè)務(wù)操作、利用響應(yīng)對(duì)象響應(yīng)客戶端請(qǐng)
求摹菠。

getServletInfo():返回Servlet相關(guān)信息盒卸,如Servlet 名稱(chēng)、作者次氨、版本等信
息蔽介。

destroy():當(dāng)容器監(jiān)測(cè)到一個(gè)Servlet 服務(wù)從容器中被移除,容器調(diào)用該方
法煮寡、釋放資源虹蓄、該方法只能被調(diào)用一次。

3.3 Servlet 生命周期

  • 初始化 階段調(diào)用 init() 方法
  • 響應(yīng)客戶端請(qǐng)求 階段調(diào)用 service() 方法
  • 終止 階段調(diào)用destroy方法

3.4 Servlet幸撕、ServletConfig薇组、GenericServlet、HttpServlet

  • 頂層接口Servlet坐儿、ServletConfig律胀、
  • GenericServlet 實(shí)現(xiàn) implements 上述兩個(gè)頂層接口、
  • ServletConfig 中聲明 getServletContext方法挑童、
  • Servlet 中聲明 getServletConfig 方法累铅、
  • HttpServlet extend GenericServlet;

所以在Servlet 中獲取servletContext對(duì)象的方法有以下兩種方式:
方式一

ServletContext servletContext = getServletContext();

方式二

ServletContext servletContext = getServletConfig().getServletContext()l;

4.HttpServlet 源碼解析

4.1 HttpServlet實(shí)例域
HttpServlet 是繼承自 GenericServlet 的抽象類(lèi)
實(shí)例域定義如下圖所示:

HttpServlet
  • GET : 獲取由請(qǐng)求 URL 標(biāo)識(shí)的資源
  • POST : 向 Web 服務(wù)器發(fā)送無(wú)限制長(zhǎng)度的數(shù)據(jù)
  • PUT : 存儲(chǔ)一個(gè)資源到請(qǐng)求的 URL
  • DELETE : 刪除由 URL 標(biāo)識(shí)的資源
  • HEAD : 返回 URL 標(biāo)識(shí)的頭信息
  • OPTIONS : 返回服務(wù)器支持的 HTTP 方法
  • TRACE : 返回 TRACE 請(qǐng)求附帶的頭字段

4.2 對(duì)應(yīng)的服務(wù)方法

  • doGet():調(diào)用服務(wù)器的資源站叼,并將其作為響應(yīng)返回給客戶端娃兽。doGet() 操作會(huì)將url 中顯式傳遞的參數(shù) 傳遞給 Servlet,Servlet 通過(guò) getRequestParam(paramName) 獲取相關(guān)參數(shù)尽楔,這在系統(tǒng)的安全方面可能帶來(lái)一些問(wèn)題, 比如說(shuō), 用戶登錄時(shí), 表單里的用戶名和密碼需要發(fā)送到服務(wù)器端, doGet() 調(diào)用會(huì)在瀏覽器的 URL 里顯示用戶名和密碼.
  • doPost() : 它用于把客戶端的數(shù)據(jù)傳給服務(wù)端, 使用它可以以隱藏方式給服務(wù)器端發(fā)送數(shù)據(jù). Post 適合發(fā)送大量數(shù)據(jù).
  • doPut() : 調(diào)用和 doPost() 相似, 并且它允許客戶端把真正的文件存放在服務(wù)器上, 而不僅僅是傳送數(shù)據(jù).
  • doDelete() : 它允許客戶端刪除服務(wù)器端的文件或者 Web 頁(yè)面.它的使用非常少.
  • doHead() : 它用于處理客戶端的 Head 調(diào)用,并且返回一個(gè) response. 當(dāng)客戶端只需要響應(yīng)的 Header 時(shí),它就發(fā)出一個(gè)Header 請(qǐng)求.這種情況下客戶端往往關(guān)心響應(yīng)的長(zhǎng)度和響應(yīng)的 MIME 類(lèi)型.
  • doOptions(): 它用于處理客戶端的 Options 調(diào)用,通過(guò)這個(gè)調(diào)用, 客戶端可以獲得此 Servlet 支持的方法.如果 Servlet 覆蓋了 doPost() 方法, 那么將返回: Allow: POST, TRACE, OPTIONS, HEAD
  • doTrace:處理 TRACE 請(qǐng)求

4.3 HttpServlet 實(shí)現(xiàn) Servlet 中的Servlet方法

@Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {

        HttpServletRequest  request;
        HttpServletResponse response;

        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }
       //HttpServlet 重載 的Service() 方法投储,使用到了編譯時(shí)多態(tài),因?yàn)閰?shù)類(lèi)型不一樣阔馋。
        service(request, response);

    }
}

4.4 HttpServlet 重載的 Service() 方法

protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        // 從 HTTP 請(qǐng)求中取得這次請(qǐng)求所使用的 HTTT 方法
        String method = req.getMethod();
        // 如果這次請(qǐng)求使用 GET 方法
        if (method.equals(METHOD_GET)) {
            // 取得這個(gè) Servlet 的最后修改的時(shí)間
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                //-1 代表這個(gè) Servlet 不支持最后修改操作玛荞,直接調(diào)用 doGet() 進(jìn)行處理 HTTP GET 請(qǐng)求
                doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    // 如果這個(gè) Servlet 支持最后修改操作,取得請(qǐng)求頭中包含的請(qǐng)求的最后修改時(shí)間
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    // Invalid date header - proceed as if none was set
                    ifModifiedSince = -1;
                }
                  // 如果請(qǐng)求頭中包含的修改時(shí)間早于這個(gè) Servlet 的最后修改時(shí)間呕寝,說(shuō)明這個(gè) Servlet 自從客戶上一次 HTTP 請(qǐng)求已經(jīng)被修改了 , 設(shè)置最新修改時(shí)間到響應(yīng)頭中
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);

        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);

        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);

        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);

        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);

        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);

            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

5.Servlet 是否是線程安全的

Servlet 是線程非安全的勋眯。這是單例模式的通病。

因?yàn)閟ervlet對(duì)象是單例模式的創(chuàng)建型對(duì)象下梢,在一次Servlet Container 啟停過(guò)程中客蹋,整個(gè) Servlet 生命周期內(nèi)只維持一個(gè)Servlet對(duì)象,而對(duì)于每一個(gè)請(qǐng)求應(yīng)用服務(wù)器都會(huì)從線程池中excute 一個(gè)線程去執(zhí)行一個(gè)runnertask(request請(qǐng)求)
所以如果在一個(gè)Servlet中定義了實(shí)例域孽江,那么就會(huì)產(chǎn)生多線程并發(fā)修改共享變量的線程安全問(wèn)題讶坯,解決這個(gè)問(wèn)題的辦法是對(duì)多線程對(duì)共享變量的操作采用同步操作,或者采用ThreadLocal 將每個(gè)線程與其自身的變量綁定在一起岗屏。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末辆琅,一起剝皮案震驚了整個(gè)濱河市漱办,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌婉烟,老刑警劉巖娩井,帶你破解...
    沈念sama閱讀 222,378評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異隅很,居然都是意外死亡撞牢,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)叔营,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)屋彪,“玉大人,你說(shuō)我怎么就攤上這事绒尊⌒蠡樱” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,983評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵婴谱,是天一觀的道長(zhǎng)蟹但。 經(jīng)常有香客問(wèn)我,道長(zhǎng)谭羔,這世上最難降的妖魔是什么华糖? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,938評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮瘟裸,結(jié)果婚禮上客叉,老公的妹妹穿的比我還像新娘。我一直安慰自己话告,他們只是感情好兼搏,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著沙郭,像睡著了一般佛呻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上病线,一...
    開(kāi)封第一講書(shū)人閱讀 52,549評(píng)論 1 312
  • 那天吓著,我揣著相機(jī)與錄音,去河邊找鬼送挑。 笑死夜矗,一個(gè)胖子當(dāng)著我的面吹牛驮履,可吹牛的內(nèi)容都是我干的圃阳。 我是一名探鬼主播氓润,決...
    沈念sama閱讀 41,063評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼赡突!你這毒婦竟也來(lái)了对扶?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,991評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤惭缰,失蹤者是張志新(化名)和其女友劉穎浪南,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體漱受,經(jīng)...
    沈念sama閱讀 46,522評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡络凿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昂羡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片絮记。...
    茶點(diǎn)故事閱讀 40,742評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖虐先,靈堂內(nèi)的尸體忽然破棺而出怨愤,到底是詐尸還是另有隱情,我是刑警寧澤蛹批,帶...
    沈念sama閱讀 36,413評(píng)論 5 351
  • 正文 年R本政府宣布撰洗,位于F島的核電站,受9級(jí)特大地震影響腐芍,放射性物質(zhì)發(fā)生泄漏差导。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評(píng)論 3 335
  • 文/蒙蒙 一猪勇、第九天 我趴在偏房一處隱蔽的房頂上張望设褐。 院中可真熱鬧,春花似錦埠对、人聲如沸络断。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,572評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)貌笨。三九已至,卻和暖如春襟沮,著一層夾襖步出監(jiān)牢的瞬間锥惋,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,671評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工开伏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留膀跌,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,159評(píng)論 3 378
  • 正文 我出身青樓固灵,卻偏偏與公主長(zhǎng)得像捅伤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子巫玻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • Servlet接口: Servlet主要方法: init()--ServletConfig servlet實(shí)例化后...
    cxm11閱讀 723評(píng)論 0 3
  • 本文包括: Servlet簡(jiǎn)介關(guān)于Servlet的一些類(lèi) Servlet生命周期 ServletConfig獲得初...
    廖少少閱讀 3,870評(píng)論 1 67
  • servlet是運(yùn)行在web服務(wù)器或應(yīng)用服務(wù)器上的組件丛忆,用于接收請(qǐng)求(主要是http請(qǐng)求)和響應(yīng)請(qǐng)求的祠汇,它是 數(shù)據(jù)...
    n油炸小朋友閱讀 321評(píng)論 0 0
  • 目標(biāo) servlet的生命周期 servletConfig與ServletContext定義,及其二者的區(qū)別 監(jiān)聽(tīng)...
    arkulo閱讀 971評(píng)論 0 5
  • 從三月份找實(shí)習(xí)到現(xiàn)在熄诡,面了一些公司可很,掛了不少,但最終還是拿到小米凰浮、百度我抠、阿里、京東袜茧、新浪菜拓、CVTE、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,278評(píng)論 11 349