Servlet第二篇【Servlet調用圖、Servlet細節、ServletConfig、ServletContext】

Servlet的調用圖

前面咱們已經學過了Servlet的生命週期了,咱們根據Servlet的生命週期畫出Servlet的調用圖加深理解php

Servlet的細節

一個已經註冊的Servlet能夠被屢次映射

同一個Servlet能夠被映射到多個URL上。java

<servlet>
            <servlet-name>Demo1</servlet-name>
            <servlet-class>zhongfucheng.web.Demo1</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>Demo1</servlet-name>
            <url-pattern>/Demo1</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>Demo1</servlet-name>
            <url-pattern>/ouzicheng</url-pattern>
        </servlet-mapping>

不管我訪問的是http://localhost:8080/Demo1仍是http://localhost:8080/ouzicheng。我訪問的都是Demo1。web

Servlet映射的URL可使用通配符

通配符有兩種格式:數據庫

  1. *.擴展名
  2. 正斜槓(/)開頭並以「/*」結尾。

匹配全部apache

匹配擴展名爲.jsp的編程

若是.擴展名和正斜槓(/)開頭並以「/」結尾兩種通配符同時出現,匹配的是哪個呢?瀏覽器

  1. 看誰的匹配度高,誰就被選擇
  2. *.擴展名的優先級最低

Servlet映射的URL可使用通配符和Servlet能夠被映射到多個URL上的做用:安全

  1. 隱藏網站是用什麼編程語言寫的【.php,.net,.asp實際上訪問的都是同一個資源】
  2. 用特定的後綴聲明版權【公司縮寫】
<servlet>
            <servlet-name>Demo1</servlet-name>
            <servlet-class>zhongfucheng.web.Demo1</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>Demo1</servlet-name>
            <url-pattern>*.jsp</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>Demo1</servlet-name>
            <url-pattern>*.net</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>Demo1</servlet-name>
            <url-pattern>*.asp</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>Demo1</servlet-name>
            <url-pattern>*.php</url-pattern>
        </servlet-mapping>

Servlet是單例的

爲何Servlet是單例的

瀏覽器屢次對Servlet的請求,通常狀況下,服務器只建立一個Servlet對象,也就是說,Servlet對象一旦建立了,就會駐留在內存中,爲後續的請求作服務,直到服務器關閉服務器

每次訪問請求對象和響應對象都是新的

對於每次訪問請求,Servlet引擎都會建立一個新的HttpServletRequest請求對象和一個新的HttpServletResponse響應對象,而後將這兩個對象做爲參數傳遞給它調用的Servlet的service()方法service方法再根據請求方式分別調用doXXX方法markdown

線程安全問題

當多個用戶訪問Servlet的時候,服務器會爲每一個用戶建立一個線程當多個用戶併發訪問Servlet共享資源的時候就會出現線程安全問題

原則:

  1. 若是一個變量須要多個用戶共享,則應當在訪問該變量的時候,加同步機制synchronized (對象){}
  2. 若是一個變量不須要共享,則直接在 doGet() 或者 doPost()定義.這樣不會存在線程安全問題

load-on-startup

若是在元素中配置了一個元素,那麼WEB應用程序在啓動時,就會裝載並建立Servlet的實例對象、以及調用Servlet實例對象的init()方法

做用:

  1. 爲web應用寫一個InitServlet,這個servlet配置爲啓動時裝載,爲整個web應用建立必要的數據庫表和數據
  2. 完成一些定時的任務【定時寫日誌,定時備份數據】

在web訪問任何資源都是在訪問Servlet

當你啓動Tomcat,你在網址上輸入http://localhost:8080。爲何會出現Tomcat小貓的頁面?

這是由缺省Servlet爲你服務的

  • 咱們先看一下web.xml文件中的配置,web.xml文件配置了一個缺省Servlet
<servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>


    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
  • 什麼叫作缺省Servlet?凡是在web.xml文件中找不到匹配的元素的URL,它們的訪問請求都將交給缺省Servlet處理,也就是說,缺省Servlet用於處理全部其餘Servlet都不處理的訪問請求
  • 既然我說了在web訪問任何資源都是在訪問Servlet,那麼我訪問靜態資源【本地圖片,本地HTML文件】也是在訪問這個缺省Servlet【DefaultServlet】
  • 證明一下:當我沒有手工配置缺省Servlet的時候,訪問本地圖片是能夠訪問獲得的

  • 如今我本身配置一個缺省Servlet,Demo1就是我手工配置的缺省Servlet,覆蓋掉web.xml配置的缺省Servlet
<servlet>
        <servlet-name>Demo1</servlet-name>
        <servlet-class>zhongfucheng.web.Demo1</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Demo1</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
  • 下面我繼續訪問一下剛纔的圖片,此時輸出的是Demo1這個Servlet寫上的內容了

  • 總結:不管在web中訪問什麼資源【包括JSP】,都是在訪問Servlet。沒有手工配置缺省Servlet的時候,你訪問靜態圖片,靜態網頁,缺省Servlet會在你web站點中尋找該圖片或網頁,若是有就返回給瀏覽器,沒有就報404錯誤

ServletConfig對象

ServletConfig對象有什麼用?

經過此對象能夠讀取web.xml中配置的初始化參數。

如今問題來了,爲何咱們要把參數信息放到web.xml文件中呢?咱們能夠直接在程序中均可以定義參數信息,搞到web.xml文件中又有什麼好處呢

好處就是:可以讓你的程序更加靈活【更換需求,更改配置文件web.xml便可,程序代碼不用改】

獲取web.xml文件配置的參數信息

  • 爲Demo1這個Servlet配置一個參數,參數名是name,值是zhongfucheng
<servlet>
        <servlet-name>Demo1</servlet-name>
        <servlet-class>zhongfucheng.web.Demo1</servlet-class>
        <init-param>
            <param-name>name</param-name>
            <param-value>zhongfucheng</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>Demo1</servlet-name>
        <url-pattern>/Demo1</url-pattern>
    </servlet-mapping>
  • 在Servlet中獲取ServletConfig對象,經過ServletConfig對象獲取在web.xml文件配置的參數

ServletContext對象

什麼是ServletContext對象?

當Tomcat啓動的時候,就會建立一個ServletContext對象。它表明着當前web站點

ServletContext有什麼用?

  1. ServletContext既然表明着當前web站點,那麼全部Servlet都共享着一個ServletContext對象,因此Servlet之間能夠經過ServletContext實現通信
  2. ServletConfig獲取的是配置的是單個Servlet的參數信息,ServletContext能夠獲取的是配置整個web站點的參數信息
  3. 利用ServletContext讀取web站點的資源文件
  4. 實現Servlet的轉發【用ServletContext轉發很少,主要用request轉發】

Servlet之間實現通信

ServletContext對象能夠被稱之爲域對象

到這裏可能有一個疑問,域對象是什麼呢?其實域對象能夠簡單理解成一個容器【相似於Map集合】

實現Servlet之間通信就要用到ServletContext的setAttribute(String name,Object obj)方法
第一個參數是關鍵字,第二個參數是你要存儲的對象

  • 這是Demo2的代碼
//獲取到ServletContext對象
        ServletContext servletContext = this.getServletContext();

        String value = "zhongfucheng";

        //MyName做爲關鍵字,value做爲值存進 域對象【類型於Map集合】
        servletContext.setAttribute("MyName", value);
  • 這是Demo3的代碼
//獲取ServletContext對象
        ServletContext servletContext = this.getServletContext();

        //經過關鍵字獲取存儲在域對象的值
        String value = (String) servletContext.getAttribute("MyName");

        System.out.println(value);
  • 訪問Demo3能夠獲取Demo2存儲的信息,從而實現多個Servlet之間通信


獲取web站點配置的信息

若是我想要讓全部的Servlet都可以獲取到鏈接數據庫的信息,不可能在web.xml文件中每一個Servlet中都配置一下,這樣代碼量太大了!而且會顯得很是囉嗦冗餘。

  • web.xml文件支持對整個站點進行配置參數信息全部Servlet均可以取到該參數信息
<context-param>
        <param-name>name</param-name>
        <param-value>zhongfucheng</param-value>
    </context-param>
  • Demo4代碼
//獲取到ServletContext對象
        ServletContext servletContext = this.getServletContext();

        //經過名稱獲取值
        String value = servletContext.getInitParameter("name");
        System.out.println(value);

  • 試一下Demo3是否能拿到,相同的代碼
//獲取到ServletContext對象
        ServletContext servletContext = this.getServletContext();

        //經過名稱獲取值
        String value = servletContext.getInitParameter("name");
        System.out.println(value);


讀取資源文件

第一種方式:

  • 如今我要經過Servlet111讀取1.png圖片

  • 按咱們之前的方式,代碼應該是這樣的。
FileInputStream fileInputStream = new FileInputStream("1.png");
        System.out.println(fileInputStream);
  • 當咱們訪問的時候,卻出錯了!說找不到1.png文件

  • 這是爲何呢?咱們之前讀取文件的時候,若是程序和文件在同一包名,能夠直接經過文件名稱獲取獲得的!,緣由很簡單,之前咱們寫的程序都是經過JVM來運行的,而如今,咱們是經過Tomcat來運行的
  • 根據web的目錄規範,Servlet編譯後的class文件是存放在WEB-INF\classes文件夾中的

  • 看到這裏,咱們知道了要進入classes目錄中讀取文件,因此咱們將代碼改爲如下方式
 FileInputStream fileInputStream = new FileInputStream("D:\\zhongfucheng\\web\\WEB-INF\\classes\\zhongfucheng\\web\\1.png"); System.out.println(fileInputStream); 
  • 再去讀取時,就發現能夠獲取到文件了。
  • 可是如今問題又來了,我讀取文件的時候都要寫上絕對路徑,這樣太不靈活了。試想一下,若是我將該讀取文件的模塊移到其餘的web站點上個人代碼就又要修改了【由於web站點的名字不同】
  • 咱們經過ServletContext讀取就能夠避免修改代碼的狀況,由於ServletContext對象是根據當前web站點而生成的
  • 代碼以下所示:
//獲取到ServletContext對象
        ServletContext servletContext = this.getServletContext();

        //調用ServletContext方法獲取到讀取文件的流
        InputStream inputStream = servletContext.getResourceAsStream("/WEB-INF/classes/zhongfucheng/web/1.png");


第二種方式:

  • 若是個人文件放在web目錄下,那麼就簡單得多了!,直接經過文件名稱就能獲取

  • 代碼以下所示
 //獲取到ServletContext對象 ServletContext servletContext = this.getServletContext(); //調用ServletContext方法獲取到讀取文件的流 InputStream inputStream = servletContext.getResourceAsStream("2.png"); 


第三種方式:

經過類裝載器讀取資源文件

  • 個人文件放在了src目錄下【也叫作類目錄】

  • 代碼以下所示
//獲取到類裝載器
        ClassLoader classLoader = Servlet111.class.getClassLoader();

        //經過類裝載器獲取到讀取文件流
        InputStream inputStream = classLoader.getResourceAsStream("3.png");

  • 個人文件放在了src目錄下的包下

  • 代碼以下,添加包名路徑便可。
//獲取到類裝載器
        ClassLoader classLoader = Servlet111.class.getClassLoader();

        //經過類裝載器獲取到讀取文件流
        InputStream inputStream = classLoader.getResourceAsStream("/zhongfucheng/web/1.png");

原則:若是文件太大,就不能用類裝載器的方式去讀取,會致使內存溢出

相關文章
相關標籤/搜索