初窥Servlet
1. Servlet簡介
??????? Servlet是sun公司提供的一門用于開發動態web資源的技術。sun公司在其API中提供了一個servlet接口,用戶若想要發一個動態web資源,只需要完成以下兩步即可:
?????????? 1)編寫一個servlet,即實現servlet接口的Java類;
?????????? 2) 把開發好的servlet部署到web服務器中。
??????? Servlet接口定義了所有servlet必須實現的方法。一個servlet是運行在web服務器中的一個小java程序,servlet通過HTTP協議接收并響應web客戶端發來的請求。這個接口中定義的方法包括初始化servlet,服務請求,以及remove servlet,這些方法即servlet的生命周期方法,調用順序如下:
?????????? 1)某個創建servlet對象的時候,調用初始化方法: void init(ServletConfig config)
?????? ??? 2)客戶端發送請求的時候,service方法被執行:void service(ServletRequest req, ServletResponse res)
?????? ? ? 3)某個servlet對象被摧毀的時候,調用destroy方法: void destroy()
??????? 除了這些與生命周期有關的方法外,Servlet接口還提供了getServletConfig方法和getServletInfo方法,getServletConfig方法可以獲得servlet的一些啟動信息,getServletInfo方法可以返回servlet本身的一些信息。
??????? sun公司定義了Servlet接口的兩個默認實現類,分別為javax.servlet.GenericServlet和javax.servlet.http.HttpServlet。
??????? HttpServlet指能夠處理HTTP請求的servlet,它再原有的Servlet接口上添加了一些與HTTP協議處理方法,它比Servlet接口的功能更為強大,因此開發人員在編寫Servlet時,通常應繼承這個類,而避免直接去實現Servlet接口。HttpServlet在實現Servlet接口時,覆寫了service方法,該方法體內的代碼會自動判斷用戶的請求方式,如為GET請求,則調用HttpServlet的doGet方法,如為Post請求,則調用doPost方法。因此,開發人員在編寫Servlet時,通常只需要覆寫doGet或doPost方法,而不要去覆寫service方法。
2. Servlet的運行過程
??????? Servlet程序是由web服務器調用,web服務器接收到客戶端的Servlet訪問請求后:
?????????? 1)web服務器首先檢查是否已經裝載并創建了該Servlet的實例對象,如果是,則直接執行第4步,否則執行第2步。
? ? ? ? ?? 2)裝載并創建該Servlet的一個實例對象。
? ? ? ? ?? 3)調用Servlet實例對象的init()方法。
? ? ? ? ?? 4)創建一個用于封裝HTTP請求消息的HttpServletRequest對象和一個代表HTTP相應消息的HttpServletResponse對象,然后調用Servlet的service()方法并將請求和響應對象作為參數傳遞進去。
? ? ? ? ?? 5)web應用程序被停止或重新啟動前,Servlet引擎將卸載Servlet,并在卸載之前調用Servlet的destroy()方法。
3. Servlet的幾個細節
1. Servlet細節1
??????? 由于客戶端是通過URL地址訪問文本服務器中的資源,所以servlet程序若想被外界訪問,必須把servlet程序映射到一個URL地址上,這個工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。
?????? 1) <servlet>元素用于注冊Servlet,它包含兩個主要的子元素:
????????????? <servlet-name>:用于設置Servlet的注冊名稱
????????????? <servlet-class>:用于設置Servlet的完整類名
??????? 2)<servlet-mapping>元素用于映射一個已注冊的Servlet的一個對外訪問路徑,它包含兩個子元素:
????????????? <servlet-name>:用于設置Servlet的注冊名稱
????????????? <url-pattern>:用于指定Servlet的對外訪問路徑(可以隨便指定)
????????例如:
<web-app> <servlet> <servlet-name>AnyName</servlet-name> <servlet-class>HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>AnyName</servlet-name> <url-pattern>/demo/hello.html</url-pattern> </servlet-mapping> </web-app>2. Servlet細節2
??????? 同一個Servlet可以被映射到多個URL上,即多個<servlet-mapping>元素的<servlet-name>子元素的設置值可以是同一個Servlet的注冊名。在Servlet映射到的URL中也可以使用*通配符,但是只能有兩種固定的格式:一種格式是:“*.擴展名”;另一種格式是:以“/”開頭,并以“/*”結尾。例如:
<servlet-mapping> <servlet-name>AnyName</servlet-name> <url-pattern>*do</url-pattern> </servlet-mapping>?也可以映射到另一個url:
<servlet-mapping> <servlet-name>AnyName</servlet-name> <url-pattern>/action/*</url-pattern> </servlet-mapping>3. servlet細節3
??????? Servlet是一個供其他java程序(Servlet引擎)調用的java類,它不能獨立運行,它的運行完全由Servlet引擎來控制和調度。針對客戶端的多次Servlet請求,通常情況下,服務器只會創建一個Servlet實例對象,也就是說Servlet實例對象一旦創建,它就會駐留在內存中,為后續的其它請求服務,直至web容器退出,servlet實例對象才銷毀。
??????? 在Servlet的整個生命周期中,Servlet的init方法只被調用一次,而對一個Servlet的每次訪問請求都導致Servlet引擎調用一次servlet的service方法。對于每次訪問請求,Servlet引擎都會創建一個新的HttpServletRequest請求對象和一個新的HttpServletResponse響應對象,然后將這兩個對象作為參數傳遞給它調用的Servlet的service()方法,service方法再根據請求方式分別調用doGet或doPost方法。
4. servlet細節4
??????? 如果再<servlet>元素中配置了一個<load-on-startup>元素,那么web應用程序在啟動時,就會裝載并創建Servlet的實例對象,以及調用Servlet實例對象的init()方法。該技術可以用來為web寫一個initServlet,這個servlet配置為啟動時裝載,為整個web應用床架必要的數據庫表和數據。如:
<servlet> <servlet-name>...</servlet-name> <servlet-class>...</servlet-class> <load-on-startup>1<load-on-startiup> </servlet>5. servlet細節5
??????? 如果某個Servlet的映射路徑僅僅為一個正斜杠(/),那么這個Servlet就成為當前Web應用程序的缺省Servlet。凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的url,它們的訪問請求都將交給缺省Servlet處理,也就是說,缺省Servlet用于處理所有其他Servlet都不處理的訪問請求。
??????? 在<tomcat安裝目錄>\conf\web.xml文件中,注冊了一個名稱為org.apache.catalina.servlets.DefaulServlet的Servlet,并將這個Servlet設置為了缺省Servlet。當訪問Tomcat服務器中的某個靜態HTML文件和圖片時,實際上是在訪問這個缺省Servlet。
??????? 假設現在在工程名為test的WebRoot目錄下新建一個1.html,在web.xml文件中并沒有配置<servlet-mapping>,即在工程中沒有Servlet映射成1.html,然后訪問:http://localhost:8080/test/1.html時,這時候這個請求就交給缺省的Servlet,缺省的Servlet收到請求后,會首先看一下web應用下面有沒有這個1.html,如果有則讀取并返回到瀏覽器,如果沒有則返回一個錯誤頁面。
6. servlet細節6
??????? 當多個客戶端并發訪問同一個Servlet時,web服務器會為每一個客戶端的訪問請求創建一個線程,并在這個線程上調用Servlet的service方法,因為Servlet只有一個實例化對象,因此service方法內如果訪問了同一個資源的話,就有可能引發線程安全問題。那么如何解決Servlet中的線程安全問題呢?
?????? 1) 如果某個Servlet實現了SingleThreadModel接口,那么Servlet引擎將以單線程模式來調用其service方法。該接口沒有任何方法,它起到了一個標志的作用。對于實現了SingleThreadModel接口的Servlet,Servlet引擎仍然支持對該Servlet的多線成并發訪問,其采用的方式是產生多個Servlet實例對象,并發的每個線程分別調用一個獨立Servlet實例對象。
?????? 2)使用synchronized 關鍵字,synchronized能保證一次只有一個線程可以訪問被保護的區段,從而可以通過同步塊操作來保證線程的安全。
?????? 3)盡量避免在Servlet里使用實例變量,只要在Servlet里面的任何方法里面都不使用共有的實例變量,那么該Servlet就是線程安全的。
? ? ???以上三種方式中,實現SingleThreadModel接口可以解決問題,但是并不是真正解決Servlet的線程安全問題,因為Servlet引擎會創建多個Servlet實例對象,而真正意義上解決多線程安全問題是指一個Servlet實例對象被多個線程同時調用的問題。另外,創建多個Servlet實例對象也會引起大量的開銷。事實上,在Servlet API 2.4中,已經將SingleThreadModel標記為過時的了。
????????同樣,如果在程序中使用同步來保護要使用的共享的數據,也會使系統的性能大大下降。這是因為被同步的代碼塊在同一時刻只能有一個線程執行它,使得其同時處理客戶請求的吞吐量降低,而且很多客戶處于阻塞狀態。所以在實際的開發中也應避免或最小化 Servlet 中的同步代碼。
????????所以,在Servlet中避免使用實例變量是保證Servlet線程安全的最佳選擇。
3. Servlet的Hello Word
??????? 最后寫一個再簡單不過的Hello Word吧……
public class ServletDemo extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("Hello word!"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }?web.xml:
<servlet> <servlet-name>ServletDemo</servlet-name> <servlet-class>servlet.ServletDemo</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>ServletDemo</servlet-name> <url-pattern>/ServletDemo</url-pattern> </servlet-mapping>入門就這么多吧,如有錯誤之處,歡迎留言指正~
總結
- 上一篇: 实现仿简书选取内容生成分享图片效果
- 下一篇: vim cscope taglist 使