java基礎學習:JavaWeb之Servlet

其餘更多java基礎文章:
java基礎學習(目錄)html


什麼是Servlet

Servlet是一個特殊的Java類, 是運行在 Web 服務器中的小型 Java 程序(即:服務器端的小應用程序)。servlet 一般經過 HTTP(超文本傳輸協議)接收和響應來自 Web 客戶端的請求。這個Java類必須繼承HttpServlet。每一個Servlet能夠響應客戶端的請求,Servlet提供不一樣的方法用於響應客戶端請求,例如doGet,doPost,doPut等java

Tomcat與Servlet的關係

Tomcat 是Web應用服務器,是一個Servlet/JSP容器. Tomcat 做爲Servlet容器,負責處理客戶請求,把請求傳送給Servlet,並將Servlet的響應傳送回給客戶.而Servlet是一種運行在支持Java語言的服務器上的組件.。web

Servlet最多見的用途是擴展Java Web服務器功能,提供很是安全的,可移植的,易於使用的CGI替代品。 從http協議中的請求和響應能夠得知,瀏覽器發出的請求是一個請求文本,而瀏覽器接收到的也應該是一個響應文本。 spring

image

  1. Tomcat將http請求文本接收並解析,而後封裝成HttpServletRequest類型的request對象,全部的HTTP頭數據讀能夠經過request對象調用對應的方法查詢到。
  2. Tomcat同時會要響應的信息封裝爲HttpServletResponse類型的response對象,經過設置response屬性就能夠控制要輸出到瀏覽器的內容,而後將response交給tomcat,tomcat就會將其變成響應文本的格式發送給瀏覽器。

Java Servlet API 是Servlet容器(tomcat)和servlet之間的接口,它定義了serlvet的各類方法,還定義了Servlet容器傳送給Servlet的對象類,其中最重要的就是ServletRequest和ServletResponse。因此說咱們在編寫servlet時,須要實現Servlet接口,按照其規範進行操做。瀏覽器

Servlet執行過程

  在瀏覽器的地址欄輸入:http://ip:port/appNames/servlet緩存

  1)經過瀏覽器和ip:port和這個服務器創建鏈接。
  2) 瀏覽器會生成一個請求數據包(路徑appNames/servlet)向服務器發送請求。
  3) 服務器收到請求數據包,分析請求資源路徑作精準定位,經過請求的appName查找webapps文件下面的appName作匹配,匹配上了須要獲取web.xml中的servlet(mapping)。 
  4) 服務器建立兩個對象:
    第一個對象:請求對象,該對象實現了HttpServletRequest接口,服務器會將請求數據包中的數據解析出來,存儲在該對象裏。這樣作的好處是沒有必要理解http協議,只須要讀取request。
    第二個對象:響應對象,實現了HttpServletResponse接口,做用是servlet處理完成後的結果能夠存放到該對象上,而後服務器依據該對象的數據生成響應數據包。
  5) servlet在執行servlet()方法時,能夠經過request獲取請求數據,也能夠將處理結果存放到response上。而後服務器與響應對象直接造成一個默契,生成一個響應數據包給瀏覽器。
  6)瀏覽器解析服務器返回的響應數據包,生成響應的結果。tomcat

  

image

Servlet訪問的過程:
Http請求---->web.xml--------> url -pattern----->servlet-name----->servlet-class-----> QuickStratServlet(對應的Class文件)安全

Servlet的生命週期

Servlet生命週期可分爲5個步驟springboot

  1. 加載Servlet。當Tomcat第一次訪問Servlet的時候,Tomcat會負責建立Servlet的實例
  2. 初始化。當Servlet被實例化後,Tomcat會調用init()方法初始化這個對象
  3. 處理服務。當瀏覽器訪問Servlet的時候,Servlet 會調用service()方法處理請求
  4. 銷燬。當Tomcat關閉時或者檢測到Servlet要從Tomcat刪除的時候會自動調用destroy()方法,讓該實例釋放掉所佔的資源。一個Servlet若是長時間不被使用的話,也會被Tomcat自動銷燬
  5. 卸載。當Servlet調用完destroy()方法後,等待垃圾回收。若是有須要再次使用這個Servlet,會從新調用init()方法進行初始化操做。

簡單總結:只要訪問Servlet,service()就會被調用。init()只有第一次訪問Servlet的時候纔會被調用。 destroy()只有在Tomcat關閉的時候纔會被調用。bash

Servlet的配置

使用配置文件
  1. 寫Servlet類
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.service(req, resp);
    }
}
複製代碼
  1. 在web.xml中配置Servlet
    image.png
    ######使用springboot
  2. 寫servlet類
  3. 在springboot啓動類配置
@SpringBootApplication
public class ServletApp {

    @Bean
    public ServletRegistrationBean MyServlet(){
        return new ServletRegistrationBean(new MyServlet(),"/myserv/*");
    }

    public static void main(String[] args){
        SpringApplication.run(ServletApp.class, args);
    }
}
複製代碼

#Servlet細節

  • Servlet的url匹配順序

當一個請求發送到servlet容器的時候,容器先會將請求的url減去當前應用上下文的路徑做爲servlet的映射url,好比我訪問的是http://localhost/hiway/user/aaa.html,個人應用上下文是hiway,容器會將http://localhost/hiway去掉,剩下的/user/aaa.html部分拿來作servlet的映射匹配。這個映射匹配過程是有順序的,並且當有一個servlet匹配成功之後,就不會去理會剩下的servlet了。其匹配規則和順序以下:

  1. 精確路徑匹配。例子:好比servletA 的url-pattern爲 /test,servletB的url-pattern爲 /* ,這個時候,若是我訪問的url爲http://localhost/test ,這個時候容器就會先進行精確路徑匹配,發現/test正好被servletA精確匹配,那麼就去調用servletA,也不會去理會其餘的servlet了。
  2. 最長路徑匹配。例子:servletA的url-pattern爲/test/,而servletB的url-pattern爲/test/a/,此時訪問http://localhost/test/a時,容器會選擇路徑最長的servlet來匹配,也就是這裏的servletB。
  3. 擴展匹配。 若是url最後一段包含擴展,容器將會根據擴展選擇合適的servlet。例子:servletA的url-pattern:*.action
  4. 最後, 若是前面三條規則都沒有找到一個servlet,容器會根據url選擇對應的請求資源。若是應用定義了一個default servlet,則容器會將請求丟給default servlet
  • Servlet是單例的嗎

在Servlet規範中,對於Servlet單例與多例定義以下:

「Deployment Descriptor」, controls how the servlet container provides instances of the servlet.For a servlet not hosted in a distributed environment (the default), the servlet container must use only one instance per servlet declaration. However, for a servlet implementing the SingleThreadModel interface, the servlet container may instantiate multiple instances to handle a heavy request load and serialize requests to a particular instance.

上面規範提到: 若是一個Servlet沒有被部署在分佈式的環境中,通常web.xml中聲明的一個Servlet只對應一個實例。 而若是一個Servlet實現了SingleThreadModel接口,就會被初始化多個實例。默認20個

因此我的理解Servlet不算單例,只是容器讓它只實例化一次,變現出來的是單例的效果而已

  • #####如何開發線程安全的Servlet
  1. 實現 SingleThreadModel 接口
  2. 使用synchronized同步對共享數據的操做
  3. 避免使用實例變量

對上面的三種方法進行測試,能夠代表用它們都能設計出線程安全的Servlet程序。可是,若是一個Servlet實現了SingleThreadModel接口,Servlet引擎將爲每一個新的請求建立一個單獨的Servlet實例,這將引發大量的系統開銷。SingleThreadModel在Servlet2.4中已再也不提倡使用;一樣若是在程序中使用同步來保護要使用的共享的數據,也會使系統的性能大大降低。這是由於被同步的代碼塊在同一時刻只能有一個線程執行它,使得其同時處理客戶請求的吞吐量下降,並且不少客戶處於阻塞狀態。另外爲保證主存內容和線程的工做內存中的數據的一致性,要頻繁地刷新緩存,這也會大大地影響系統的性能。因此在實際的開發中也應避免或最小化 Servlet 中的同步代碼;**在Serlet中避免使用實例變量是保證Servlet線程安全的最佳選擇。**從Java 內存模型也能夠知道,方法中的臨時變量是在棧上分配空間,並且每一個線程都有本身私有的棧空間,因此它們不會影響線程的安全

學習資料:lixh1986.iteye.com/blog/235569…

  • Servlet的<load-on-startup>

在servlet的配置當中,

<load-on-startup>1</load-on-startup>
複製代碼

的含義是:
標記容器是否在啓動的時候就加載這個servlet。當值爲0或者大於0時,表示容器在應用啓動時就加載這個servlet;當是一個負數時或者沒有指定時,則指示容器在該servlet被選擇時才加載。正數的值越小,啓動該servlet的優先級越高。
配置load-on-startup後,servlet在startup後當即加載,但只是調用servlet的init()方法,用以初始化該servlet相關的資源。初始化成功後,該servlet可響應web請求;如未配置load-on-startup,容器通常在第一次響應web請求時,會先檢測該servlet是否初始化,如未初始化,則調用servlet的init()先初始化,初始化成功後,再響應請求。

  • 缺省default Servlet

能夠將url-pattern 配置一個/,表明該servlet是缺省的servlet。什麼是缺省的servlet? 當你訪問資源地址全部的servlet都不匹配時,缺省的servlet賦值處理。其實,web應用中全部的資源的響應都是servlet負責,包括靜態資源(html頁面)。(有配置缺省的servlet,沒法訪問到靜態資源。)

學習資料:www.cnblogs.com/zhangyinhua…

相關文章
相關標籤/搜索