1. 程式人生 > >Servlet學習筆記(一)之Servlet原理、初始化、生命週期、結構體系

Servlet學習筆記(一)之Servlet原理、初始化、生命週期、結構體系

Servlet是用java語言編寫的應用到Web伺服器端的擴充套件技術,與java物件的區別是,Servlet物件主要封裝了對HTTP請求的處理,並且它的執行需要Servlet容器的支援(以下會介紹原因,也可以看之前的一篇介紹Servlet容器的部落格,(http://blog.csdn.net/megustas_jjc/article/details/52923132)),在JavaWeb中,Servlet主要用於處理各種業務邏輯,並且還可以輸出HTML程式碼來顯示指定頁面。
Servlet 用來 動態web資源 開發:
靜態web資源 : 固定資料檔案
動態web資源 : 通過程式動態生成資料檔案

Servlet技術基於Request-Response程式設計模型 ,HTTP協議也是基於請求響應 模型 ,

新航道託福因此 Servlet技術 用來 開發基於HTTP web 應用程式 。

接觸 JavaEE API ------ 程式 介面 和 已經實現介面 類的 使用 (JavaEE ---- Java Platform, Enterprise Edition 縮寫 )

建立一個簡單servlet的步驟:
1、建立web project
2、編寫 class 繼承 HttpServlet
3、在web.xml 配置 Servlet程式 虛擬訪問路徑 (使用者在瀏覽器上通過這個路徑 訪問編寫Servlet程式 )
4、覆蓋doGet或者doPost方法 進行輸出
其中,Servlet程式在編寫和執行時,需要javaee 類庫 (API支援),例如在學習javase List 需要 import java.util.List 需要 jre/lib/rt.jar,對於eclipse需要自行匯入jar包,先要找到檔案所在的路徑,如下。


C:\Tomcat 5.0\common\lib\servlet-api.jar。 然後在eclipse裡面 Project ->Properties,在左邊找到Java Builder Path,單擊,在右邊找到Libraries,然後Add External Jars,找到C:\Tomcat 5.0\common\lib\servlet-api.jar。完畢,接著可以使用 import javax.servlet.*

Servlet執行原理分析
編寫Servlet程式沒有 main函式(意味著不能獨立執行,需要tomcat) ---- tomcat呼叫Servlet程式執行

這裡寫圖片描述

1、使用者在客戶端發起url請求 : http://localhost/day05/hello 。


2、web.xml /hello 對映 HelloServlet程式。
3、使用者提交請求時,get方式提交執行HelloServlet的doGet方法,post方式提交執行 HelloServlet的doPost 方法 。

手動編寫Servlet執行(servlet在執行時需要依賴外界的jar包)
手動編寫Servlet執行(servlet在執行時需要依賴外界的jar包)
1、在webapps 新建 day05test目錄 — 虛擬應用
2、在day05test 新建 WEB-INF/classes
3、將編寫Servlet的java原始碼檔案 放入 classes ,在 WEB-INF 配置web.xml (進行虛擬路徑配置)
4、編譯Servlet的 java程式
javac -classpath E:\apache-tomcat-6.0.14\lib\servlet-api.jar HelloServlet.java // 通過 -classpath 指定 Servlet需要jar 包
生成Servlet package結構
javac -d . -classpath E:\apache-tomcat-6.0.14\lib\servlet-api.jar HelloServlet.java

Servlet生命週期與初始化

(1)Servlet生命週期
(2)init(ServletConfig config) 初始化
(3)service(ServletRequest req, ServletResponse res) 提供服務方法
(4)destroy() 銷燬

 

原理:
1、tomcat伺服器啟動時,沒有建立Servlet物件
2、第一次訪問時,tomcat構造Servlet物件,呼叫 init,執行service
3、從第二次以後訪問 tomcat 不會從新建立Servlet物件,也不會呼叫init ---- 每一次訪問都會呼叫service
4、當伺服器重啟或正常關閉時 呼叫destroy (正常關閉 shutdown.bat)

這裡寫圖片描述

servlet生命週期小結:

  • 針對客戶端多次Servlet請求,通常情況下**,伺服器只會建立一個Servlet例項物件**,雅思初級也就是說Servlet例項物件一旦建立,它就會駐留在記憶體中,為後續的其他請求服務,直至web容器退出,servlet例項物件才會銷燬。
  • 在整個Servlet生命週期內,Servlet的init方法只被呼叫一次。而對一個Servlet的每次訪問請求導致Servlet引擎呼叫一次servlet的service方法,對於每次訪問請求,Servlet引擎都會建立一個新的HttpServletRequest請求物件和一個HttpServletResponse響應物件,然後將這兩個物件作為引數傳遞給它呼叫的Servlet的service()方法,service方法再根據請求方式分別呼叫doXXX方法。

因此,Servlet物件是tomcat建立的,每次請求呼叫Servlet中service方法,tomcat伺服器會在每次呼叫Servlet的service方法時,為該方法建立Request物件和Response物件(在 JavaEE API 中沒有Request和Response實現類(HttpServlet是包裝類,因此不能產生Servlet物件) ----- 實現類由Servlet伺服器提供的,tomcat提供實現類 weblogic 提供實現類 ) 。

service方法 和 HttpServlet doGet/doPost 關係區別
在HttpServlet程式碼實現中,根據請求方式不同 呼叫相應doXXX方法 get方式請求 — doGet post方式 — doPost (必須閱讀HttpServlet原始碼 )

其中可以通過對Servlet進行配置,使其啟動時進行初始化,而不是之前的呼叫時進行初始化,其實現可以通過< load-on-startup>(< load-on-startup > 引數可以是一個數字 0-9 代表伺服器載入優先順序 0 最高 ,例如:在tomcat啟動時,想通過Servlet載入一些框架配置檔案 配置隨伺服器啟動 )

 

Servlet結構體系
這裡寫圖片描述

GenericServlet和HttpServlet都是Servlet介面的兩個預設實現類,GenericServlet對Servlet介面及ServletConfig介面提供了部分實現,但是並沒有對Http請求處理進行實現,這一操作由其子類HttpServlet進行實現,其為Http請求中的POST、GET等型別提供了具體的操作方法,所以通常情況下,編寫的Servlet物件都是繼承與HttpServlet。因此,編寫Servlet 不需要覆蓋service方法,只需要覆蓋doGet和doPost 方法;Servlet初始化時覆蓋init() ,無需覆蓋init(config),因為init(Config) 呼叫了init()。並且,當doGet方法與doPost方法邏輯相同時,可以互相呼叫,簡化程式設計,例如:

 

一般Servlet只初始化一次(只有一個例項)。對於更多的客戶端請求,Server建立新的請求和響應物件,仍然啟用此Servlet的service()方法,將這兩個物件作為引數傳遞給該方法。如此重複以上的迴圈,但無需再呼叫init()方法(Web容器收到請求後,Web容器會產生一個新的執行緒來呼叫Servlet的service(),service()方法檢查HTTP請求型別(GET、POST、PUT、DELETE等),雅思輔導班然後相應呼叫doGet()、doPost()、doPut()、doDelete()等方法,即用多個執行緒去執行各個請求)。

原因:

出於效能的考慮:特別的對於入口網站而言,每一個Servlet在每一秒內的併發訪問量都可以是成千上萬的。在一個面向模組化開發的現在,常常一個點選操作就被定義為一個Servlet的實現,而如果Servlet的每一次被訪問,都建立一個新的例項的話,伺服器的可用資源消耗量將是一個相當重要的問題。
退一步,一般Servlet的訪問是很快的,每一個例項被快速的建立,又被快速的回收,GC的回收速度也跟不上,頻繁的記憶體操作也將可能帶來次生的問題。

所以,Servlet的“單一例項化”是一個很重要的策略。

問題描述:
寫一個Servlet物件,使用不同的瀏覽器瀏覽時,重新整理,會出現資料安全問題。由於servlet物件只有一個,其中的屬性很容易稱為servlet方法執行的臨界資源,儘可能不要在Servlet中定義成員變數
解決方法:
在servlet中新增同步程式碼塊

 

最近在複習web相關的內容,將遇到的問題通過網上一些文章和參考用書進行了一個整理,整理為如下內容:
首先我們先來看如下的一個例子,現在假設有兩個jsp頁面,jsp1與jsp2:

jsp1頁面

jsp2頁面:

會發現無法顯示test,因為在jsp2頁面中找不到test,那麼原因是什麼呢?

其實那就要從request的生命週期或者是說作用範圍說起了,setAttribute()用來在同一個request週期中儲存變數使用。

比如servlet呼叫後,引出JSP頁面,這是一個request週期。如果在Jsp頁面需要servlet中的一些 處理結構,就從request.getAttribute中獲取。
而sendRedirect()方法是通過瀏覽器重定向的,所以第二個JSP頁面中獲得的request並非是前一個頁面的request(兩次請求生成了前後兩個不同的 request物件了)。而此時使用RequestDispatcher介面的forward()方法則能夠得到request中的物件了,這是因為後者並不是使用客戶端瀏覽器進行重定向的,從函式的名字就可以看出,RequestDispatcher.forward()就是從伺服器端進行任務轉發。

sendRedirect()是請求從定向,和超連線是一個意思,比如你在A頁面中寫一個request.setAtribute,sendRedirect到B頁面,就是說伺服器從A頁面中給你一個response,然後你的瀏覽器再去request到B頁面,由於有兩次request和response,是不能在B頁面取到request.setAtribute裡的值,能從位址列看到url的改變。

request.getRequestDispatcher().forward(request,response)是請求分發器,比如你在A頁面中寫一個request.setAtribute,request.getRequestDispatcher().forward(request,response)到B頁面,那就是說伺服器給你的response是B頁面的,並且只有一次request和response,所以是能在B頁面取到request.setAtribute裡的值,位址列的url仍然是A頁面的。

所以通常情況下,setAttribute()方法都和RequestDispatcher.forward()都在一起使用,具體用法示例:

request.setAttribute()和request.getAttribute()配對使用,作用域是請求和被請求頁面之間。雅思機經request.setAttribute()是隻在此action的下一個forward需要使用的時候使用;request.getAttribute()表示從request範圍取得設定的屬性,必須要先setAttribute設定屬性,才能通過getAttribute來取得,設定與取得的為Object物件型別。其實表單控制元件中的Object的 name與value是存放在一個雜湊表中的,所以在這裡給出Object的name會到雜湊表中找出對應它的value。setAttribute()的引數是String和Object。

sendRedirect不能傳遞request物件。使用request.setAttribute時不能使redirect而是forward。即是將請求轉發而不是重定向。

request.getParameter()表示接收引數,引數為頁面提交的引數。包括:表單提交的引數、URL重寫(就是xxx?id=1中的id)傳的引數等,因此這個並沒有設定引數的方法(沒有setParameter()),而且接收引數返回的不是Object,而是String型別。

(1)request.getParameter()取得是通過容器的實現來取得通過類似post,get等方式傳入的資料,request.setAttribute()和getAttribute()只是在web容器內部流轉,僅僅是請求處理階段
(2)request.getParameter()方法傳遞的資料,會從Web客戶端傳到Web伺服器端,代表HTTP請求資料。request.getParameter()方法返回String型別的資料。
request.setAttribute()和getAttribute()方法傳遞的資料只會存在於Web容器內部
還有一點就是,HttpServletRequest類有setAttribute()方法,而沒有setParameter()方法。
拿一個例子來說一下吧,假如兩個WEB頁面間為連結關係時,就是說要從1.jsp連結到2.jsp時,出國留學中介被連結的是2.jsp可以通過getParameter()方法來獲得請求引數.

假如1.jsp裡有

請輸入使用者姓名:

的話在2.jsp中通過request.getParameter(“username”)方法來獲得請求引數username:
<% String username=request.getParameter(“username”); %>


但是如果兩個WEB間為轉發關係時,轉發目的WEB可以用getAttribute()方法來和轉發源WEB共享request範圍內的資料,也還是說一個例子吧。
有1.jsp和2.jsp
1.jsp希望向2.jsp傳遞當前的使用者名稱字,如何傳遞這一資料呢?先在1.jsp中呼叫如下setAttribute()方法:

在2.jsp中通過getAttribute()方法獲得使用者名稱字:
<% String username=(String)request.getAttribute(“username”); %>

不同頁面間傳值使用request.setAttribute(position, nameOfObj)時,只會從a.jsp到b.jsp一次傳遞,之後這個request 就會失去它的作用範圍,再傳就要再設一個 request.setAttribute()。而使用session.setAttribute()會在一個過程中始終保有這個值。
session.setAttribute()和session.getAttribute()配對使用,作用域是整個會話期間,在所有的頁面都使用這些資料的時候使用。詳細的session相關內容可以參考http://blog.csdn.net/megustas_jjc/article/details/53443012。