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