javaweb學習筆記(三):Servlet
Servlet的詳細解讀目錄
Servlet詳解
1.Servlet概述與執行過程
由於客戶端是通過URL地址訪問web伺服器中的資源,所以Servlet程式若想被外界訪問,必須把servlet程式對映到一個URL地址上,這個工作在web.xml檔案中使用<servlet>
<servlet-mapping>
元素完成。<servlet>
元素用於註冊Servlet,它包含有兩個主要的子元素:<servlet-name>
和<servlet-class>
,分別用於設定Servlet的註冊名稱和Servlet的完整類名。
一個<servlet-mapping>
元素用於對映一個已註冊的Servlet的一個對外訪問路徑,它包含有兩個子元素:<servlet-name>
和<url-pattern>
,分別用於指定Servlet的註冊名稱和Servlet的對外訪問路徑。
<web-app> <servlet> <servlet-name>AnyName</servlet-name> <servlet-class>HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>AnyName</servlet> <url-pattern>/demo/hello</url-pattern> </servlet-mapping> </web-app>
Servlet程式是由WEB伺服器呼叫,web伺服器收到客戶端的Servlet訪問請求後:
①Web伺服器首先檢查是否已經裝載並建立了該Servlet的例項物件。如果是,則直接執行第④步,否則,執行第②步。
②裝載並建立該Servlet的一個例項物件。
③呼叫Servlet例項物件的init()方法。
④建立一個用於封裝HTTP請求訊息的HttpServletRequest物件和一個代表HTTP響應訊息的HttpServletResponse物件,然後呼叫Servlet的service()方法並將請求和響應物件作為引數傳遞進去。
⑤WEB應用程式被停止或重新啟動之前,Servlet引擎將解除安裝Servlet,並在解除安裝之前呼叫Servlet的destroy()方法。
2.Servlet對映路徑
- url-pattern要麼以 / 開頭,要麼以
*
開頭。 - 不能同時使用兩種模糊匹配(
/*
和*.do
),例如/hello/*.do
是非法路徑 - 當有輸入的URL有多個servlet同時被匹配的情況下:
3.1 精確匹配優先。
3.2 以後綴名結尾的模糊url-pattern優先順序最低!!!(/*
高於*.do
)
關於預設路徑:
servlet的預設路徑(<url-pattern>/</url-pattern>
)是在tomcat伺服器內建的一個路徑。該路徑對應的是一個DefaultServlet(預設Servlet)。這個預設的Servlet的作用是用於解析web應用的靜態資原始檔。
URL輸入http://localhost:8080/Test/index.html
1)到當前Test應用下的web.xml檔案查詢是否有匹配的url-pattern。
2)如果沒有匹配的url-pattern,則交給tomcat的內建的DefaultServlet處理
3)DefaultServlet程式到Test應用的根目錄下查詢是存在一個名稱為index.html的靜態檔案。
4)若找到該檔案,則讀取該檔案內容,返回給瀏覽器;如果找不到,則返回404錯誤頁面。
結論: 先找動態資源,再找靜態資源。
3.Servlet 的生命週期
3.1生命週期方法
Servlet程式的生命週期由tomcat伺服器控制!!
Servlet重要的4個生命週期方法:
- 構造方法: 建立servlet物件的時候呼叫。預設情況下,第一次訪問servlet的時 候建立servlet物件。只調用1次。證明servlet物件在tomcat是單例項的。
- init方法(帶參): 建立完servlet物件的時候呼叫。只調用1次。
- service方法: 每次發出請求時呼叫。呼叫n次。
- destroy方法: 銷燬servlet物件的時候呼叫。停止伺服器或者重新部署web應用 時銷燬servlet物件。只調用1次。
注:①帶參的init方法,是servlet的生命週期方法,一定會被tomcat伺服器呼叫,且其會預設呼叫無參的init方法。一般不重寫。
②若要編寫初始化程式碼,需覆蓋無參的init方法,在裡面編寫即可。
3.2虛擬碼演示生命週期
- 通過對映找到servlet-class的內容,字串:gz.a_servlet.FirstServlet
- 通過反射構造FirstServlet物件
2.1 得到位元組碼物件
Class clazz = class.forName(“gz.itcast.a_servlet.FirstServlet”);
2.2 呼叫無引數的構造方法來構造物件
Object obj = clazz.newInstance(); servlet的構造方法被呼叫 - 建立ServletConfig物件,通過反射呼叫init方法
3.1得到方法物件
Method m = clazz.getDeclareMethod(“init”,ServletConfig.class);
3.2 呼叫方法
m.invoke(obj,config); servlet的init帶參方法被呼叫 - 建立request,response物件,通過反射呼叫service方法
4.1 得到方法物件
Methodm m=clazz.getDeclareMethod(“service”,HttpServletRequest.class,HttpServletResponse.class);
4.2 呼叫方法
m.invoke(obj,request,response); servlet的service方法被呼叫 - 當tomcat伺服器停止或web應用重新部署,通過反射呼叫destroy方法
5.1 得到方法物件
Method m = clazz.getDeclareMethod(“destroy”,null);
5.2 呼叫方法
m.invoke(obj,null); servlet的destroy方法被呼叫
4.自動載入
預設情況下,第一次訪問servlet時建立servlet物件。如果servlet的構造方法或init方法中執行了比較多的邏輯程式碼,那麼使用者第一次訪問sevrlet的時候比較慢。解決辦法就是改變servlet建立物件的時機:提前到載入web應用的時候(tomcat啟動時)!
在servlet的配置資訊中,加上一個即可!注:整數值越大,建立的優先順序越低。
<servlet>
<servlet-name>LifeDemo</servlet-name>
<servlet-class>gz.c_life.LifeDemo</servlet-class>
<!-- 讓servlet物件自動載入 -->
<load-on-startup>1</load-on-startup>
</servlet>
如果WEB應用啟動時就需要啟動某個框架程式,那麼可以把框架程式的啟動程式碼放到一個Servlet的init方法中,併為這個Servlet配置</load-on-startup>
。這樣的話,當WEB應用啟動時,框架也將隨之啟動。例如struts框架採用的就是這種啟動方式。
5.併發問題
servlet物件在tomcat伺服器是單例項多執行緒的。
因為servlet是多執行緒的,所以當多個servlet的執行緒同時訪問了servlet的共享資料,如成員變數,可能會引發執行緒安全問題。
解決辦法:把使用到共享資料的程式碼塊進行同步(使用synchronized關鍵字進行同步),建議在servlet類中儘量不要使用成員變數。如果確實要使用成員,必須同步。而且儘量縮小同步程式碼塊的範圍。以避免因為同步而導致併發效率降低。
6.ServletConfig物件
主要是用於載入servlet的初始化引數。在一個web應用可以存在多個ServletConfig物件(一個Servlet對應一個ServletConfig物件)。建立時機為在建立完servlet物件之後,在呼叫init方法之前。獲得物件的途徑為直接從有引數的init方法中得到。
servlet的初始化引數在servlet中配置, 這些引數會在載入web應用的時候(啟動tomcat伺服器),封裝到ServletConfig物件中。
注: servlet的引數只能由當前的這個sevlet獲取!
<servlet>
<servlet-name>ConfigDemo</servlet-name>
<servlet-class>gz.f_config.ConfigDemo</servlet-class>
<!-- 初始引數: -->
<init-param>
<param-name>path</param-name>
<param-value>e:/b.txt</param-value>
</init-param>
</servlet>
ServletConfig的API:
java.lang.String getInitParameter(java.lang.String name) 根據引數名獲取引數值
java.util.Enumeration getInitParameterNames() 獲取所有引數名
ServletContext getServletContext() 得到servletContex物件
java.lang.String getServletName() 得到servlet的名稱
7. ServletContext物件
ServletContext物件 ,叫做Servlet的上下文物件。表示一個當前的web應用環境。一個web應用中只有一個ServletContext物件。建立時機為在載入web應用時建立ServletContext物件。獲得物件的途徑為從ServletConfig物件的getServletContext方法得到。
<web-app>
<!-- 在web-app之下配置web應用引數 -->
<context-param>
<param-name>AAA</param-name>
<param-value>AAA's value</param-value>
</context-param>
<context-param>
<param-name>BBB</param-name>
<param-value>BBB's value</param-value>
</context-param>
<servlet>......</servlet>
<servlet-mapping>...... </servlet-mapping>
</web-app>
ServletContext物件的核心API(作用)
- 得到當前web應用的路徑,用在請求重定向的資原始檔中。
java.lang.String getContextPath() - web應用的初始化引數,可以讓當前web應用的所有servlet獲取!
java.lang.String getInitParameter(java.lang.String name) java.util.Enumeration getInitParameterNames() - 域物件的作用是儲存資料,獲取資料。可以在不同的動態資源之間共享資料。
四個域物件:
HttpServletRequet
ServletContext :在整個web應用中有效
HttpSession
PageContext
方法有:
void setAttribute(java.lang.String name, java.lan g.Object object)
java.lang.Object getAttribute(java.lang.String name)
void removeAttribute(java.lang.String name)
- 轉發:如果要使用HttpServletRequest域物件進行資料共享,只能用轉發技術。
轉發與重定向的區別:
a)轉發的位址列不會改變;而重定向位址列會改變,變成重定向到的地址。
b)轉發只能轉發到當前web應用內的資源;重定向可以跳轉到當前web應用,或其他web應用,甚至是外部域名網站。
c)可以在轉發過程中,把資料儲存到HttpServletRequest域物件中;而不可以在重定向過程中,把資料儲存到HttpServletRequest域物件中。
RequestDispatcher getRequestDispatcher(java.lang.String path)
轉發:一個web資源收到客戶端請求後,通知伺服器去呼叫另外一個web資源進行處理。
重定向:一個web資源收到客戶端請求後,通知瀏覽器去訪問另外一個web資源。
區別:
RequestDispatcher.forward方法只能將請求轉發給同一個WEB應用中的元件;而HttpServletResponse.sendRedirect 方法還可以重定向到同一個站點上的其他應用程式中的資源,甚至是使用絕對URL重定向到其他站點的資源。
如果傳遞給HttpServletResponse.sendRedirect 方法的相對URL以“/”開頭,它是相對於整個WEB站點的根目錄;如果建立RequestDispatcher物件時指定的相對URL以“/”開頭,它是相對於當前WEB應用程式的根目錄。
呼叫HttpServletResponse.sendRedirect方法重定向的訪問過程結束後,瀏覽器位址列中顯示的URL會發生改變,由初始的URL地址變成重定向的目標URL;呼叫RequestDispatcher.forward 方法的請求轉發過程結束後,瀏覽器位址列保持初始的URL地址不變。
HttpServletResponse.sendRedirect方法對瀏覽器的請求直接作出響應,響應的結果就是告訴瀏覽器去重新發出對另外一個URL的訪問請求;RequestDispatcher.forward方法在伺服器端內部將請求轉發給另外一個資源,瀏覽器只知道發出了請求並得到了響應結果,並不知道在伺服器程式內部發生了轉發行為。
RequestDispatcher.forward方法的呼叫者與被呼叫者之間共享相同的request物件和response物件,它們屬於同一個訪問請求和響應過程;而HttpServletResponse.sendRedirect方法呼叫者與被呼叫者使用各自的request物件和response物件,它們屬於兩個獨立的訪問請求和響應過程。
- 得到web應用的資原始檔
java.lang.String getRealPath(java.lang.String path)
java.io.InputStream getResourceAsStream(java.lang.String path)