Servlet简介
Servlet程序是由WEB服務(wù)器調(diào)用,web服務(wù)器收到客戶端的Servlet訪問(wèn)請(qǐng)求后:
①Web服務(wù)器首先檢查是否已經(jīng)裝載并創(chuàng)建了該Servlet的實(shí)例對(duì)象。如果是,則直接執(zhí)行第④步,否則,執(zhí)行第②步。
②裝載并創(chuàng)建該Servlet的一個(gè)實(shí)例對(duì)象。?
③調(diào)用Servlet實(shí)例對(duì)象的init()方法。
④創(chuàng)建一個(gè)用于封裝HTTP請(qǐng)求消息的HttpServletRequest對(duì)象和一個(gè)代表HTTP響應(yīng)消息的HttpServletResponse對(duì)象,然后調(diào)用Servlet的service()方法并將請(qǐng)求和響應(yīng) ? ? ? ? ? 對(duì)象作為參數(shù)傳遞進(jìn)去。
⑤WEB應(yīng)用程序被停止或重新啟動(dòng)之前,Servlet引擎將卸載Servlet,并在卸載之前調(diào)用Servlet的destroy()方法。
?
在eclipse中新建一個(gè)web project工程,eclipse會(huì)自動(dòng)創(chuàng)建下圖所示目錄結(jié)構(gòu):
接口實(shí)現(xiàn)類
Servlet接口SUN公司定義了兩個(gè)默認(rèn)實(shí)現(xiàn)類,分別為:GenericServlet、HttpServlet。
HttpServlet指能夠處理HTTP請(qǐng)求的servlet,它在原有Servlet接口上添加了一些與HTTP協(xié)議處理方法,它比Servlet接口的功能更為強(qiáng)大。因此開(kāi)發(fā)人員在編寫(xiě)Servlet時(shí),通常應(yīng)繼承這個(gè)類,而避免直接去實(shí)現(xiàn)Servlet接口。
HttpServlet在實(shí)現(xiàn)Servlet接口時(shí),覆寫(xiě)了service方法,該方法體內(nèi)的代碼會(huì)自動(dòng)判斷用戶的請(qǐng)求方式,如為GET請(qǐng)求,則調(diào)用HttpServlet的doGet方法,如為Post請(qǐng)求,則調(diào)用doPost方法。因此,開(kāi)發(fā)人員在編寫(xiě)Servlet時(shí),通常只需要覆寫(xiě)doGet或doPost方法,而不要去覆寫(xiě)service方法。
通過(guò)Eclipse創(chuàng)建和編寫(xiě)Servlet
選中g(shù)acl.servlet.study包,右鍵→New→Servlet,如下圖所示:
這樣,我們就通過(guò)Eclipse幫我們創(chuàng)建好一個(gè)名字為ServletDemo1的Servlet,創(chuàng)建好的ServletDemo01里面會(huì)有如下代碼:
1 package gacl.servlet.study;2 3 import java.io.IOException;4 import java.io.PrintWriter;5 6 import javax.servlet.ServletException;7 import javax.servlet.http.HttpServlet;8 import javax.servlet.http.HttpServletRequest;9 import javax.servlet.http.HttpServletResponse; 10 11 public class ServletDemo1 extends HttpServlet { 12 13 /** 14 * The doGet method of the servlet. <br> 15 * 16 * This method is called when a form has its tag value method equals to get. 17 * 18 * @param request the request send by the client to the server 19 * @param response the response send by the server to the client 20 * @throws ServletException if an error occurred 21 * @throws IOException if an error occurred 22 */ 23 public void doGet(HttpServletRequest request, HttpServletResponse response) 24 throws ServletException, IOException { 25 26 response.setContentType("text/html"); 27 PrintWriter out = response.getWriter(); 28 out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"); 29 out.println("<HTML>"); 30 out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>"); 31 out.println(" <BODY>"); 32 out.print(" This is "); 33 out.print(this.getClass()); 34 out.println(", using the GET method"); 35 out.println(" </BODY>"); 36 out.println("</HTML>"); 37 out.flush(); 38 out.close(); 39 } 40 41 /** 42 * The doPost method of the servlet. <br> 43 * 44 * This method is called when a form has its tag value method equals to post. 45 * 46 * @param request the request send by the client to the server 47 * @param response the response send by the server to the client 48 * @throws ServletException if an error occurred 49 * @throws IOException if an error occurred 50 */ 51 public void doPost(HttpServletRequest request, HttpServletResponse response) 52 throws ServletException, IOException { 53 54 response.setContentType("text/html"); 55 PrintWriter out = response.getWriter(); 56 out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"); 57 out.println("<HTML>"); 58 out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>"); 59 out.println(" <BODY>"); 60 out.print(" This is "); 61 out.print(this.getClass()); 62 out.println(", using the POST method"); 63 out.println(" </BODY>"); 64 out.println("</HTML>"); 65 out.flush(); 66 out.close(); 67 } 68 69 }這些代碼都是Eclipse自動(dòng)生成的,而web.xml文件中也多了<servlet></servlet>和<servlet-mapping></servlet-mapping>兩對(duì)標(biāo)簽,這兩對(duì)標(biāo)簽是配置ServletDemo1的,如下圖所示:
然后我們就可以通過(guò)瀏覽器訪問(wèn)ServletDemo1這個(gè)Servlet,如下圖所示:
?
同一個(gè)Servlet可以被映射到多個(gè)URL上,即多個(gè)<servlet-mapping>元素的<servlet-name>子元素的設(shè)置值可以是同一個(gè)Servlet的注冊(cè)名
1 <servlet>2 <servlet-name>ServletDemo1</servlet-name>3 <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class>4 </servlet>5 6 <servlet-mapping>7 <servlet-name>ServletDemo1</servlet-name>8 <url-pattern>/servlet/ServletDemo1</url-pattern>9 </servlet-mapping> 10 <servlet-mapping> 11 <servlet-name>ServletDemo1</servlet-name> 12 <url-pattern>/1.htm</url-pattern> 13 </servlet-mapping> 14 <servlet-mapping> 15 <servlet-name>ServletDemo1</servlet-name> 16 <url-pattern>/2.jsp</url-pattern> 17 </servlet-mapping> 18 <servlet-mapping> 19 <servlet-name>ServletDemo1</servlet-name> 20 <url-pattern>/3.php</url-pattern> 21 </servlet-mapping> 22 <servlet-mapping> 23 <servlet-name>ServletDemo1</servlet-name> 24 <url-pattern>/4.ASPX</url-pattern> 25 </servlet-mapping>通過(guò)上面的配置,當(dāng)我們想訪問(wèn)名稱是ServletDemo1的Servlet,可以使用如下的幾個(gè)地址去訪問(wèn):
http://localhost:8080/JavaWeb_Servlet_Study_20140531/servlet/ServletDemo1
http://localhost:8080/JavaWeb_Servlet_Study_20140531/1.htm
http://localhost:8080/JavaWeb_Servlet_Study_20140531/2.jsp
http://localhost:8080/JavaWeb_Servlet_Study_20140531/3.php
http://localhost:8080/JavaWeb_Servlet_Study_20140531/4.ASPX
ServletDemo1被映射到了多個(gè)URL上。
?
Servlet訪問(wèn)URL使用*通配符映射
在Servlet映射到的URL中也可以使用*通配符,但是只能有兩種固定的格式:一種格式是"*.擴(kuò)展名",另一種格式是以正斜杠(/)開(kāi)頭并以"/*"結(jié)尾。例如:
1 <servlet> 2 <servlet-name>ServletDemo1</servlet-name> 3 <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class> 4 </servlet> 5 6 <servlet-mapping> 7 <servlet-name>ServletDemo1</servlet-name> 8 <url-pattern>/*</url-pattern>
?
Servlet與普通Java類的區(qū)別
Servlet是一個(gè)供其他Java程序(Servlet引擎)調(diào)用的Java類,它不能獨(dú)立運(yùn)行,它的運(yùn)行完全由Servlet引擎來(lái)控制和調(diào)度。
針對(duì)客戶端的多次Servlet請(qǐng)求,通常情況下,服務(wù)器只會(huì)創(chuàng)建一個(gè)Servlet實(shí)例對(duì)象,也就是說(shuō)Servlet實(shí)例對(duì)象一旦創(chuàng)建,它就會(huì)駐留在內(nèi)存中,為后續(xù)的其它請(qǐng)求服務(wù),直至web容器退出,servlet實(shí)例對(duì)象才會(huì)銷毀。
在Servlet的整個(gè)生命周期內(nèi),Servlet的init方法只被調(diào)用一次。而對(duì)一個(gè)Servlet的每次訪問(wèn)請(qǐng)求都導(dǎo)致Servlet引擎調(diào)用一次servlet的service方法。對(duì)于每次訪問(wèn)請(qǐng)求,Servlet引擎都會(huì)創(chuàng)建一個(gè)新的HttpServletRequest請(qǐng)求對(duì)象和一個(gè)新的HttpServletResponse響應(yīng)對(duì)象,然后將這兩個(gè)對(duì)象作為參數(shù)傳遞給它調(diào)用的Servlet的service()方法,service方法再根據(jù)請(qǐng)求方式分別調(diào)用doXXX方法。
如果在<servlet>元素中配置了一個(gè)<load-on-startup>元素,那么WEB應(yīng)用程序在啟動(dòng)時(shí),就會(huì)裝載并創(chuàng)建Servlet的實(shí)例對(duì)象、以及調(diào)用Servlet實(shí)例對(duì)象的init()方法。
?? ?舉例:
?? ?<servlet>
?? ??? ?<servlet-name>invoker</servlet-name>
?? ??? ?<servlet-class>
?? ??? ??? ?org.apache.catalina.servlets.InvokerServlet
?? ??? ?</servlet-class>
?? ??? ?<load-on-startup>1</load-on-startup>
?? ?</servlet>
用途:為web應(yīng)用寫(xiě)一個(gè)InitServlet,這個(gè)servlet配置為啟動(dòng)時(shí)裝載,為整個(gè)web應(yīng)用創(chuàng)建必要的數(shù)據(jù)庫(kù)表和數(shù)據(jù)。
?
如下一段配置,熟悉DWR的再熟悉不過(guò)了:
<servlet>
?? <servlet-name>dwr-invoker</servlet-name>
?? <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
?? <init-param>
??? <param-name>debug</param-name>
??? <param-value>true</param-value>
?? </init-param>
?? <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
?? <servlet-name>dwr-invoker</servlet-name>
?? <url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
我們注意到它里面包含了這段配置:<load-on-startup>1</load-on-startup>,那么這個(gè)配置有什么作用呢?
貼一段英文原汁原味的解釋如下:
Servlet specification:
The load-on-startup element indicates that this servlet should be loaded (instantiated and have its init() called) on the startup of the web application. The optional contents of these element must be an integer indicating the order in which the servlet should be loaded. If the value is a negative integer, or the element is not present, the container is free to load the servlet whenever it chooses.?? If the value is a positive integer or 0, the container must load and initialize the servlet as the application is deployed. The container must guarantee that servlets marked with lower integers are loaded before servlets marked with higher integers. The container may choose the order of loading of servlets with the same load-on-start-up value.
翻譯過(guò)來(lái)的意思大致如下:
1)load-on-startup元素標(biāo)記容器是否在啟動(dòng)的時(shí)候就加載這個(gè)servlet(實(shí)例化并調(diào)用其init()方法)。
2)它的值必須是一個(gè)整數(shù),表示servlet應(yīng)該被載入的順序
2)當(dāng)值為0或者大于0時(shí),表示容器在應(yīng)用啟動(dòng)時(shí)就加載并初始化這個(gè)servlet;
3)當(dāng)值小于0或者沒(méi)有指定時(shí),則表示容器在該servlet被選擇時(shí)才會(huì)去加載。
4)正數(shù)的值越小,該servlet的優(yōu)先級(jí)越高,應(yīng)用啟動(dòng)時(shí)就越先加載。
5)當(dāng)值相同時(shí),容器就會(huì)自己選擇順序來(lái)加載。
所以,<load-on-startup>x</load-on-startup>,中x的取值1,2,3,4,5代表的是優(yōu)先級(jí),而非啟動(dòng)延遲時(shí)間。
如下題目:
2.web.xml中不包括哪些定義(多選)
?
a.默認(rèn)起始頁(yè)
b.servlet啟動(dòng)延遲時(shí)間定義
c.error處理頁(yè)面
d.jsp文件改動(dòng)后重新載入時(shí)間
答案:b,d
通常大多數(shù)Servlet是在用戶第一次請(qǐng)求的時(shí)候由應(yīng)用服務(wù)器創(chuàng)建并初始化,但<load-on-startup>n</load-on-startup>?? 可以用來(lái)改變這種狀況,根據(jù)自己需要改變加載的優(yōu)先級(jí)!
?
缺省Servlet用于處理所有其他Servlet都不處理的訪問(wèn)請(qǐng)求(在web.xml文件中找不到匹配的<servlet-mapping>元素的URL)
1 <servlet>2 <servlet-name>ServletDemo2</servlet-name>3 <servlet-class>gacl.servlet.study.ServletDemo2</servlet-class>4 <load-on-startup>1</load-on-startup>5 </servlet>6 7 <!-- 將ServletDemo2配置成缺省Servlet -->8 <servlet-mapping>9 <servlet-name>ServletDemo2</servlet-name> 10 <url-pattern>/</url-pattern> 11 </servlet-mapping>?
?
在<tomcat的安裝目錄>\conf\web.xml文件中,注冊(cè)了一個(gè)名稱為org.apache.catalina.servlets.DefaultServlet的Servlet,并將這個(gè)Servlet設(shè)置為了缺省Servlet。
1 <servlet>2 <servlet-name>default</servlet-name>3 <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>4 <init-param>5 <param-name>debug</param-name>6 <param-value>0</param-value>7 </init-param>8 <init-param>9 <param-name>listings</param-name> 10 <param-value>false</param-value> 11 </init-param> 12 <load-on-startup>1</load-on-startup> 13 </servlet> 14 15 <!-- The mapping for the default servlet --> 16 <servlet-mapping> 17 <servlet-name>default</servlet-name> 18 <url-pattern>/</url-pattern> 19 </servlet-mapping>當(dāng)訪問(wèn)Tomcat服務(wù)器中的某個(gè)靜態(tài)HTML文件和圖片時(shí),實(shí)際上是在訪問(wèn)這個(gè)缺省Servlet。
?
Servlet的線程安全問(wèn)題
當(dāng)多個(gè)客戶端并發(fā)訪問(wèn)同一個(gè)Servlet時(shí),web服務(wù)器會(huì)為每一個(gè)客戶端的訪問(wèn)請(qǐng)求創(chuàng)建一個(gè)線程,并在這個(gè)線程上調(diào)用Servlet的service方法,因此service方法內(nèi)如果訪問(wèn)了同一個(gè)資源的話,就有可能引發(fā)線程安全問(wèn)題
上面的定義的是局部變量,所以不存在線程安全問(wèn)題
?
把 i 定義成全局變量,當(dāng)多個(gè)線程并發(fā)訪問(wèn)變量i時(shí),就會(huì)存在線程安全問(wèn)題了
?
用鎖來(lái)限制
?
?
針對(duì)Servlet的線程安全問(wèn)題,Sun公司是提供有解決方案的:讓Servlet去實(shí)現(xiàn)一個(gè)SingleThreadModel接口,如果某個(gè)Servlet實(shí)現(xiàn)了SingleThreadModel接口,那么Servlet引擎將以單線程模式來(lái)調(diào)用其service方法。
查看Sevlet的API可以看到,SingleThreadModel接口中沒(méi)有定義任何方法和常量,在Java中,把沒(méi)有定義任何方法和常量的接口稱之為標(biāo)記接口,經(jīng)常看到的一個(gè)最典型的標(biāo)記接口就是"Serializable",這個(gè)接口也是沒(méi)有定義任何方法和常量的,標(biāo)記接口在Java中有什么用呢?主要作用就是給某個(gè)對(duì)象打上一個(gè)標(biāo)志,告訴JVM,這個(gè)對(duì)象可以做什么,比如實(shí)現(xiàn)了"Serializable"接口的類的對(duì)象就可以被序列化,還有一個(gè)"Cloneable"接口,這個(gè)也是一個(gè)標(biāo)記接口,在默認(rèn)情況下,Java中的對(duì)象是不允許被克隆的,就像現(xiàn)實(shí)生活中的人一樣,不允許克隆,但是只要實(shí)現(xiàn)了"Cloneable"接口,那么對(duì)象就可以被克隆了。
讓Servlet實(shí)現(xiàn)了SingleThreadModel接口,只要在Servlet類的定義中增加實(shí)現(xiàn)SingleThreadModel接口的聲明即可。 ?
對(duì)于實(shí)現(xiàn)了SingleThreadModel接口的Servlet,Servlet引擎仍然支持對(duì)該Servlet的多線程并發(fā)訪問(wèn),其采用的方式是產(chǎn)生多個(gè)Servlet實(shí)例對(duì)象,并發(fā)的每個(gè)線程分別調(diào)用一個(gè)獨(dú)立的Servlet實(shí)例對(duì)象。
實(shí)現(xiàn)SingleThreadModel接口并不能真正解決Servlet的線程安全問(wèn)題,因?yàn)镾ervlet引擎會(huì)創(chuàng)建多個(gè)Servlet實(shí)例對(duì)象,而真正意義上解決多線程安全問(wèn)題是指一個(gè)Servlet實(shí)例對(duì)象被多個(gè)線程同時(shí)調(diào)用的問(wèn)題。事實(shí)上,在Servlet API 2.4中,已經(jīng)將SingleThreadModel標(biāo)記為Deprecated(過(guò)時(shí)的)。
?
?
?
ServletConfig?配置Servlet初始化參數(shù)
?
當(dāng)servlet配置了初始化參數(shù)后,web容器在創(chuàng)建servlet實(shí)例對(duì)象時(shí),會(huì)自動(dòng)將這些初始化參數(shù)封裝到ServletConfig對(duì)象中,并在調(diào)用servlet的init方法時(shí),將ServletConfig對(duì)象傳遞給servlet。進(jìn)而,我們通過(guò)ServletConfig對(duì)象就可以得到當(dāng)前servlet的初始化參數(shù)信息。
?
?
ServletContext對(duì)象(多個(gè)Servlet通過(guò)ServletContext對(duì)象實(shí)現(xiàn)數(shù)據(jù)共享)
范例:ServletContextDemo1和ServletContextDemo2通過(guò)ServletContext對(duì)象實(shí)現(xiàn)數(shù)據(jù)共享
?
?
先運(yùn)行ServletContextDemo1,將數(shù)據(jù)data存儲(chǔ)到ServletContext對(duì)象中,然后運(yùn)行ServletContextDemo2就可以從ServletContext對(duì)象中取出數(shù)據(jù)了,這樣就實(shí)現(xiàn)了數(shù)據(jù)共享
?
獲取WEB應(yīng)用的初始化參數(shù)
?
?
?
用servletContext實(shí)現(xiàn)請(qǐng)求轉(zhuǎn)發(fā)
訪問(wèn)的是ServletContextDemo4,瀏覽器顯示的卻是ServletContextDemo5的內(nèi)容,這就是使用ServletContext實(shí)現(xiàn)了請(qǐng)求轉(zhuǎn)發(fā)
?
?
利用ServletContext對(duì)象讀取資源文件
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db1.properties");
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
?
總結(jié)
- 上一篇: winform空间批量控制
- 下一篇: bzoj1597[Usaco2008 M