簡單記錄Servlet3.0標(biāo)準(zhǔn)

背景

近段時(shí)間打算梳理一下近一年用到的SpringBoot及部分相關(guān)starter仔戈,計(jì)劃從Web入手伐蒂。要了解Java開發(fā)的Web應(yīng)用必然的從其標(biāo)準(zhǔn)(Servlet)開始遏暴。

以下內(nèi)容基本來源Oracle官網(wǎng)對(duì)Servlet3.0的介紹垦细,由于存在個(gè)人理解偏差建議讀者直接閱讀原文盒使。
地址:https://download.oracle.com/otndocs/jcp/servlet-3.0-mrel-full-oth-JSpec
備注:登錄Oracle網(wǎng)站即可將內(nèi)容以PDF的方式下載下來(簡書不支持上傳PDF文件)

概念

  • Servlet是什么矢门?
    servlet是基于Java實(shí)現(xiàn)的Web組件撒桨,servlet通過servlet容器實(shí)現(xiàn)的請(qǐng)求/響應(yīng)范式煤禽。(運(yùn)行在 Web 服務(wù)器或應(yīng)用服務(wù)器上的程序液样,它是作為來自 Web 瀏覽器或其他 HTTP 客戶端的請(qǐng)求和 HTTP 服務(wù)器上的數(shù)據(jù)庫或應(yīng)用程序之間的中間層振亮。)
  • Servlet容器是什么巧还?
    servlet容器是Web服務(wù)器或應(yīng)用程序服務(wù)器的一部分,它提供發(fā)送請(qǐng)求和響應(yīng)的網(wǎng)絡(luò)服務(wù)坊秸,基于MIME解碼請(qǐng)求麸祷,并格式化基于MIME的響應(yīng)。一個(gè)servlet容器還包含在servlet的生命周期中管理它們褒搔。

組成

  • Servlet
    1. Servlet接口是JavaServletAPI的核心抽象阶牍。所有Servlet通過擴(kuò)展一個(gè)實(shí)現(xiàn)接口。JavaServletAPI中實(shí)現(xiàn)Servlet接口是GenericServlet和HttpServlet星瘾。在大多數(shù)情況下走孽,開發(fā)人員將擴(kuò)展HttpServlet以實(shí)現(xiàn)他們的servlet。
      1.1. 通常在開發(fā)基于HTTP的Servlet時(shí)琳状,Servlet開發(fā)人員只需關(guān)注HttpServlet中的doGet和doPost方法
      1.2. JSP頁面本質(zhì)也是Servlet


      屏幕截圖 2020-04-12 19.12.14.png
    2. javax.servlet.Servlet接口(生命周期如下:)
      2.1. 由Servlet容器調(diào)用磕瓷,執(zhí)行init方法初始化Servlet,只會(huì)執(zhí)行一次念逞。
      2.2. 由servlet容器調(diào)用困食,執(zhí)行service方法響應(yīng)servlet請(qǐng)求,每次請(qǐng)求執(zhí)行一次翎承。注意:service方法是并發(fā)執(zhí)行陷舅,方法內(nèi)容需要考慮同步共享內(nèi)存
      2.3. 由servlet容器調(diào)用,執(zhí)行destroy方法銷毀Servelt审洞,只會(huì)執(zhí)行一次莱睁。
屏幕截圖 2020-04-12 18.41.25.png
  • Request

    1. 將來自客戶端請(qǐng)求的所有信息封裝為一個(gè)Request對(duì)象。在HTTP協(xié)議中芒澜,此信息通過HTTP從客戶端傳輸?shù)椒?wù)器(注意:也可以自定義其他協(xié)議實(shí)現(xiàn))
    2. javax.servlet.ServletRequest接口
      2.1. 方法getServerName:獲取當(dāng)前請(qǐng)求的域名或IP(www.ddblock.com
      2.2. 方法getServerPort:獲取當(dāng)前請(qǐng)求的端口(80)
      2.3. 方法getRemoteAddr:獲取最后一個(gè)請(qǐng)求服務(wù)端的客戶端IP仰剿,如果使用nginx反向代理時(shí)需要特殊處理一下
      2.4. 方法getRemoterHost:獲取最后一個(gè)請(qǐng)求服務(wù)端的客戶端主機(jī)名,如果使用nginx反向代理時(shí)需要特殊處理一下
      2.5. 方法getProtocol:獲取當(dāng)前請(qǐng)求的協(xié)議及其版本(HTTP/1.1)
      2.6. 方法getScheme:獲取當(dāng)前請(qǐng)求的具體協(xié)議(https)
      2.7. 方法getCharacterEncoding:獲取請(qǐng)求體內(nèi)容的編碼格式
      2.8. 方法getContentLength:獲取請(qǐng)求體內(nèi)容的字節(jié)長度
      2.9. 方法getLocale:獲取客戶端接收的語言類型
      2.10. 方法startAsync:將此請(qǐng)求置于異步模式痴晦,調(diào)用返回的AsyncContext對(duì)象的start執(zhí)行
      2.11. 方法getDispatcherType:獲取分發(fā)器類型南吮,其中包含F(xiàn)ORWARD、 INCLUDE誊酌、REQUEST部凑、ASYNC、ERROR
      2.12. 方法getServletContext:獲取上下文信息
      2.13. 方法getAsyncContext:獲取異步模式下的上下文
  • ServletContext

    1. 定義一組servlet用來與其通信的方法碧浊。例如涂邀,要獲取文件的MIME類型,分派請(qǐng)求或?qū)懭肴罩疚募淙瘛C總€(gè)Java虛擬機(jī)的每個(gè)“web應(yīng)用程序”都有一個(gè)上下文比勉。
    2. javax.servlet.ServletContext接口
      2.1. 方法getContextPath:獲取上下文根路徑
      2.2. 方法getResourcePaths:獲取指定路徑下的下級(jí)目錄集合
      2.3. 方法getMimeType:獲取指定文件的MIME類型。通過文件后綴匹配具體MIME類型,具體可參考MimeTypeMappings.properties文件(org/apache/catalina/startup/MimeTypeMappings.properties)
      2.4. 方法getRequestDispatcher:獲取指定路徑的請(qǐng)求分發(fā)器浩聋,請(qǐng)求分發(fā)器通過包裝任何類型的資源響應(yīng)給客戶端
      2.5. 方法addServlet:用于添加在web.xml观蜗、web-fragment.xml配置的Servlet或添加了WebListener注解的Servlet
      2.6. 方法addFilter:用于添加在web.xml、web-fragment.xml配置的Filter或添加了WebFilter注解的Filter
      2.7. 方法addListener:用于添加在web.xml衣洁、web-fragment.xml配置的Listener或添加了WebListener注解的ServletContextListener
  • Response

    1. 將響應(yīng)給客戶端的所有信息封裝為一個(gè)Response對(duì)象墓捻。在HTTP協(xié)議中,此信息從服務(wù)器傳輸?shù)娇蛻舳送ㄟ^HTTP頭或請(qǐng)求的消息體坊夫。
    2. javax.servlet.ServletResponse接口
      2.1. 方法getCharacterEncoding:獲取響應(yīng)body內(nèi)容的編碼格式
      2.2. 方法getContentType:獲取響應(yīng)body的內(nèi)容類型砖第。如:text/html; charset=UTF-8
      2.3. 方法setContentLength:填充響應(yīng)客戶端的響應(yīng)body的字節(jié)長度
      2.4. 方法getOutputStream:獲取ServletOutputStream對(duì)象將響應(yīng)body寫入輸出流中。getWriter方法也能實(shí)現(xiàn)相同功能践樱,但不能同時(shí)使用厂画。
      2.5. 方法getWriter:獲取PrintWriter對(duì)象將響應(yīng)body寫入輸出流中凸丸。getOutputStream方法也能實(shí)現(xiàn)相同功能拷邢,但不能同時(shí)使用。
      2.6. 方法setBufferSize:設(shè)置臨時(shí)存儲(chǔ)響應(yīng)內(nèi)容的緩沖區(qū)大小屎慢,如果設(shè)置比總響應(yīng)內(nèi)容小則響應(yīng)內(nèi)容會(huì)分多次響應(yīng)給客戶端
      2.7. 方法flushBuffer:將臨時(shí)存儲(chǔ)響應(yīng)內(nèi)容的數(shù)據(jù)及headers都發(fā)送給客戶端
  • Filter

    1. 對(duì)資源(servlet或靜態(tài)內(nèi)容)的請(qǐng)求與響應(yīng)執(zhí)行過濾任務(wù)瞭稼。過濾器在doFilter方法。每個(gè)過濾器都可以訪問一個(gè)FilterConfig對(duì)象腻惠,從中可以獲取其初始化參數(shù)环肘,以及對(duì)ServletContext的引用,該引用可以用于例如加載過濾任務(wù)所需的資源
    2. javax.servlet.Filter接口
      2.1. 由Servlet容器調(diào)用集灌,執(zhí)行init方法初始化Filter悔雹,只會(huì)執(zhí)行一次。
      2.2. 由servlet容器調(diào)用欣喧,執(zhí)行doFilter方法攔截請(qǐng)求與響應(yīng)腌零,在過濾器鏈尾端執(zhí)行servlet,每次請(qǐng)求執(zhí)行一次唆阿。
      2.3. 由servlet容器調(diào)用益涧,執(zhí)行destroy方法銷毀Filter,只會(huì)執(zhí)行一次驯鳖。
屏幕截圖 2020-04-14 22.24.52.png
  • Session
    1. 提供一種在多個(gè)頁面上標(biāo)識(shí)用戶的方法請(qǐng)求或訪問網(wǎng)站并存儲(chǔ)有關(guān)該用戶的信息闲询。 servlet容器使用此接口在HTTP客戶端和HTTP服務(wù)器之間創(chuàng)建會(huì)話。會(huì)話在指定的時(shí)間段內(nèi)持續(xù)存在浅辙,并且跨越用戶的多個(gè)連接或頁面請(qǐng)求扭弧。一個(gè)會(huì)話通常對(duì)應(yīng)一個(gè)用戶,該用戶可能會(huì)多次訪問該站點(diǎn)记舆。服務(wù)器可以通過多種方式維護(hù)會(huì)話寄狼,例如使用cookie或重寫URL。
    2. javax.servlet.http.HttpSession接口
      2.1. 方法isNew:獲取當(dāng)前請(qǐng)求是否是新的會(huì)話
      2.2. 方法getMaxInactiveInterval:返回最大時(shí)間間隔(以秒為單位),servlet容器將在客戶機(jī)訪問之間保持此會(huì)話打開泊愧。在此間隔之后伊磺,Servlet容器將使會(huì)話無效
      2.3. 方法invalidate:使該會(huì)話無效,然后取消綁定與之綁定的任何對(duì)象
      2.4. 方法getServletContext:返回此會(huì)話所屬的ServletContext
      2.5. 方法setAttribute删咱、getAttribute:用來存儲(chǔ)與獲取同一會(huì)話的數(shù)據(jù)

其它說明

  • 重要注解
    1. @WebServlet:用于定義web應(yīng)用程序中的Servlet組件
    @WebServlet(name="MyServlet", urlPatterns={"/foo", "/bar"})
    public class SampleUsingAnnotationAttributes extends HttpServlet{
        public void doGet(HttpServletRequest req, HttpServletResponse res) {
        }
    }
    
    1. @WebFilter:定義web應(yīng)用程序中的過濾器
    @WebFilter("/foo")
    public class MyFilter implements Filter {
        public void doFilter(HttpServletRequest req, HttpServletResponse res) {
        }
    }
    
    1. @WebInitParam:用于指定必須傳遞給Servlet或Filter屑埋。是WebServlet和WebFilter的一個(gè)屬性
    2. @WebListener:定義對(duì)web應(yīng)用程序上下文各類事件監(jiān)聽的監(jiān)聽器。
    javax.servlet.ServletContextListener
    javax.servlet.ServletContextAttributeListener
    javax.servlet.ServletRequestListener
    javax.servlet.ServletRequestAttributeListener
    javax.servlet.http.HttpSessionListener
    javax.servlet.http.HttpSessionAttributeListener
    
    @WebListener
    public class MyListener implements ServletContextListener{
        public void contextInitialized(ServletContextEvent sce) {
            ServletContext sc = sce.getServletContext();
            sc.addServlet("myServlet", "Sample servlet", "foo.bar.MyServlet", null, -1);
            sc.addServletMapping("myServlet", new String[] {"/urlpattern/*" });
        }
    }
    
  • javax.servlet.ServletContainerInitializer接口(基于代碼配置痰滋,而不是web.xml
    1. 提供容器初始化的擴(kuò)展邏輯摘能。容器通過jar查找在容器/應(yīng)用程序啟動(dòng)時(shí)由容器提供的服務(wù)API(如下圖META-INF/services)∏媒郑框架提供ServletContainerInitializer的實(shí)現(xiàn)必須將一個(gè)名為ServletContainerInitializer团搞,根據(jù)jar服務(wù)API,指向ServletContainerInitializer的實(shí)現(xiàn)類多艇。除了ServletContainerInitializer之外逻恐,我們還有一個(gè)注解handleTypes。實(shí)現(xiàn)handleTypes注釋ServletContainerInitializer用于表示對(duì)可能在handletype或者如果它在類的超級(jí)類型峻黍。容器使用handleTypes注釋來確定何時(shí)調(diào)用初始值設(shè)定項(xiàng)的onStartup方法
    @HandlesTypes(WebApplicationInitializer.class)
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
        @Override
        public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
            throws ServletException {
        }
    }
    

屏幕截圖 2020-04-15 23.19.56.png

2. spring-boot啟動(dòng)web容器時(shí)未按照Servlet3.0規(guī)范實(shí)現(xiàn)复隆,具體可參考(https://blog.csdn.net/weixin_34128501/article/details/92424885),其實(shí)現(xiàn)類為org.springframework.boot.web.embedded.tomcat.TomcatStarter

屏幕截圖 2020-04-15 23.30.42.png
  • javax.servlet.RequestDispatcher接口

    1. 表示從客戶端接收請(qǐng)求并將請(qǐng)求發(fā)送到服務(wù)器上的任何資源(例如servlet姆涩,HTML文件或JSP文件)的類挽拂。 包含forward與include兩種模式。
    2. forward模式:將請(qǐng)求從Servlet轉(zhuǎn)發(fā)到服務(wù)器上的另一個(gè)資源(Servlet骨饿,JSP文件或HTML文件)亏栈。這種方法允許一個(gè)Servlet對(duì)請(qǐng)求進(jìn)行初步處理,而另一種資源可以生成響應(yīng)宏赘。
    3. include模式:請(qǐng)求服務(wù)器的另外一個(gè)資源并將資源作為本Servlet輸出的子內(nèi)容
  • 事件通知

    1. 事件覆蓋了ServletContext绒北、HttpSession與ServletRequest的生命周期中。
    2. 具體事件監(jiān)聽器(混個(gè)眼熟)


      屏幕截圖 2020-04-22 23.12.26.png
      屏幕截圖 2020-04-22 23.12.13.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末置鼻,一起剝皮案震驚了整個(gè)濱河市镇饮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌箕母,老刑警劉巖储藐,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嘶是,居然都是意外死亡钙勃,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門聂喇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辖源,“玉大人蔚携,你說我怎么就攤上這事】巳模” “怎么了酝蜒?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長矾湃。 經(jīng)常有香客問我亡脑,道長,這世上最難降的妖魔是什么邀跃? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任霉咨,我火速辦了婚禮,結(jié)果婚禮上拍屑,老公的妹妹穿的比我還像新娘途戒。我一直安慰自己,他們只是感情好僵驰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布喷斋。 她就那樣靜靜地躺著,像睡著了一般矢渊。 火紅的嫁衣襯著肌膚如雪继准。 梳的紋絲不亂的頭發(fā)上枉证,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天矮男,我揣著相機(jī)與錄音,去河邊找鬼室谚。 笑死毡鉴,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秒赤。 我是一名探鬼主播猪瞬,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼入篮!你這毒婦竟也來了陈瘦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤潮售,失蹤者是張志新(化名)和其女友劉穎痊项,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酥诽,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鞍泉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肮帐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咖驮。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出托修,到底是詐尸還是另有隱情忘巧,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布睦刃,位于F島的核電站袋坑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏眯勾。R本人自食惡果不足惜枣宫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吃环。 院中可真熱鬧也颤,春花似錦、人聲如沸郁轻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽好唯。三九已至竭沫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間骑篙,已是汗流浹背蜕提。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留靶端,地道東北人谎势。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像杨名,于是被迫代替她去往敵國和親脏榆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

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