Servlet简介
Servlet程序是由WEB服務器調用,web服務器收到客戶端的Servlet訪問請求后:
?、賅eb服務器首先檢查是否已經裝載并創建了該Servlet的實例對象。如果是,則直接執行第④步,否則,執行第②步。
?、谘b載并創建該Servlet的一個實例對象。?
③調用Servlet實例對象的init()方法。
④創建一個用于封裝HTTP請求消息的HttpServletRequest對象和一個代表HTTP響應消息的HttpServletResponse對象,然后調用Servlet的service()方法并將請求和響應 ? ? ? ? ? 對象作為參數傳遞進去。
⑤WEB應用程序被停止或重新啟動之前,Servlet引擎將卸載Servlet,并在卸載之前調用Servlet的destroy()方法。
?
在eclipse中新建一個web project工程,eclipse會自動創建下圖所示目錄結構:
接口實現類
Servlet接口SUN公司定義了兩個默認實現類,分別為:GenericServlet、HttpServlet。
HttpServlet指能夠處理HTTP請求的servlet,它在原有Servlet接口上添加了一些與HTTP協議處理方法,它比Servlet接口的功能更為強大。因此開發人員在編寫Servlet時,通常應繼承這個類,而避免直接去實現Servlet接口。
HttpServlet在實現Servlet接口時,覆寫了service方法,該方法體內的代碼會自動判斷用戶的請求方式,如為GET請求,則調用HttpServlet的doGet方法,如為Post請求,則調用doPost方法。因此,開發人員在編寫Servlet時,通常只需要覆寫doGet或doPost方法,而不要去覆寫service方法。
通過Eclipse創建和編寫Servlet
選中gacl.servlet.study包,右鍵→New→Servlet,如下圖所示:
這樣,我們就通過Eclipse幫我們創建好一個名字為ServletDemo1的Servlet,創建好的ServletDemo01里面會有如下代碼:
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自動生成的,而web.xml文件中也多了<servlet></servlet>和<servlet-mapping></servlet-mapping>兩對標簽,這兩對標簽是配置ServletDemo1的,如下圖所示:
然后我們就可以通過瀏覽器訪問ServletDemo1這個Servlet,如下圖所示:
?
同一個Servlet可以被映射到多個URL上,即多個<servlet-mapping>元素的<servlet-name>子元素的設置值可以是同一個Servlet的注冊名
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>通過上面的配置,當我們想訪問名稱是ServletDemo1的Servlet,可以使用如下的幾個地址去訪問:
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被映射到了多個URL上。
?
Servlet訪問URL使用*通配符映射
在Servlet映射到的URL中也可以使用*通配符,但是只能有兩種固定的格式:一種格式是"*.擴展名",另一種格式是以正斜杠(/)開頭并以"/*"結尾。例如:
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類的區別
Servlet是一個供其他Java程序(Servlet引擎)調用的Java類,它不能獨立運行,它的運行完全由Servlet引擎來控制和調度。
針對客戶端的多次Servlet請求,通常情況下,服務器只會創建一個Servlet實例對象,也就是說Servlet實例對象一旦創建,它就會駐留在內存中,為后續的其它請求服務,直至web容器退出,servlet實例對象才會銷毀。
在Servlet的整個生命周期內,Servlet的init方法只被調用一次。而對一個Servlet的每次訪問請求都導致Servlet引擎調用一次servlet的service方法。對于每次訪問請求,Servlet引擎都會創建一個新的HttpServletRequest請求對象和一個新的HttpServletResponse響應對象,然后將這兩個對象作為參數傳遞給它調用的Servlet的service()方法,service方法再根據請求方式分別調用doXXX方法。
如果在<servlet>元素中配置了一個<load-on-startup>元素,那么WEB應用程序在啟動時,就會裝載并創建Servlet的實例對象、以及調用Servlet實例對象的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應用寫一個InitServlet,這個servlet配置為啟動時裝載,為整個web應用創建必要的數據庫表和數據。
?
如下一段配置,熟悉DWR的再熟悉不過了:
<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>,那么這個配置有什么作用呢?
貼一段英文原汁原味的解釋如下:
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.
翻譯過來的意思大致如下:
1)load-on-startup元素標記容器是否在啟動的時候就加載這個servlet(實例化并調用其init()方法)。
2)它的值必須是一個整數,表示servlet應該被載入的順序
2)當值為0或者大于0時,表示容器在應用啟動時就加載并初始化這個servlet;
3)當值小于0或者沒有指定時,則表示容器在該servlet被選擇時才會去加載。
4)正數的值越小,該servlet的優先級越高,應用啟動時就越先加載。
5)當值相同時,容器就會自己選擇順序來加載。
所以,<load-on-startup>x</load-on-startup>,中x的取值1,2,3,4,5代表的是優先級,而非啟動延遲時間。
如下題目:
2.web.xml中不包括哪些定義(多選)
?
a.默認起始頁
b.servlet啟動延遲時間定義
c.error處理頁面
d.jsp文件改動后重新載入時間
答案:b,d
通常大多數Servlet是在用戶第一次請求的時候由應用服務器創建并初始化,但<load-on-startup>n</load-on-startup>?? 可以用來改變這種狀況,根據自己需要改變加載的優先級!
?
缺省Servlet用于處理所有其他Servlet都不處理的訪問請求(在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文件中,注冊了一個名稱為org.apache.catalina.servlets.DefaultServlet的Servlet,并將這個Servlet設置為了缺省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>當訪問Tomcat服務器中的某個靜態HTML文件和圖片時,實際上是在訪問這個缺省Servlet。
?
Servlet的線程安全問題
當多個客戶端并發訪問同一個Servlet時,web服務器會為每一個客戶端的訪問請求創建一個線程,并在這個線程上調用Servlet的service方法,因此service方法內如果訪問了同一個資源的話,就有可能引發線程安全問題
上面的定義的是局部變量,所以不存在線程安全問題
?
把 i 定義成全局變量,當多個線程并發訪問變量i時,就會存在線程安全問題了
?
用鎖來限制
?
?
針對Servlet的線程安全問題,Sun公司是提供有解決方案的:讓Servlet去實現一個SingleThreadModel接口,如果某個Servlet實現了SingleThreadModel接口,那么Servlet引擎將以單線程模式來調用其service方法。
查看Sevlet的API可以看到,SingleThreadModel接口中沒有定義任何方法和常量,在Java中,把沒有定義任何方法和常量的接口稱之為標記接口,經??吹降囊粋€最典型的標記接口就是"Serializable",這個接口也是沒有定義任何方法和常量的,標記接口在Java中有什么用呢?主要作用就是給某個對象打上一個標志,告訴JVM,這個對象可以做什么,比如實現了"Serializable"接口的類的對象就可以被序列化,還有一個"Cloneable"接口,這個也是一個標記接口,在默認情況下,Java中的對象是不允許被克隆的,就像現實生活中的人一樣,不允許克隆,但是只要實現了"Cloneable"接口,那么對象就可以被克隆了。
讓Servlet實現了SingleThreadModel接口,只要在Servlet類的定義中增加實現SingleThreadModel接口的聲明即可。 ?
對于實現了SingleThreadModel接口的Servlet,Servlet引擎仍然支持對該Servlet的多線程并發訪問,其采用的方式是產生多個Servlet實例對象,并發的每個線程分別調用一個獨立的Servlet實例對象。
實現SingleThreadModel接口并不能真正解決Servlet的線程安全問題,因為Servlet引擎會創建多個Servlet實例對象,而真正意義上解決多線程安全問題是指一個Servlet實例對象被多個線程同時調用的問題。事實上,在Servlet API 2.4中,已經將SingleThreadModel標記為Deprecated(過時的)。
?
?
?
ServletConfig?配置Servlet初始化參數
?
當servlet配置了初始化參數后,web容器在創建servlet實例對象時,會自動將這些初始化參數封裝到ServletConfig對象中,并在調用servlet的init方法時,將ServletConfig對象傳遞給servlet。進而,我們通過ServletConfig對象就可以得到當前servlet的初始化參數信息。
?
?
ServletContext對象(多個Servlet通過ServletContext對象實現數據共享)
范例:ServletContextDemo1和ServletContextDemo2通過ServletContext對象實現數據共享
?
?
先運行ServletContextDemo1,將數據data存儲到ServletContext對象中,然后運行ServletContextDemo2就可以從ServletContext對象中取出數據了,這樣就實現了數據共享
?
獲取WEB應用的初始化參數
?
?
?
用servletContext實現請求轉發
訪問的是ServletContextDemo4,瀏覽器顯示的卻是ServletContextDemo5的內容,這就是使用ServletContext實現了請求轉發
?
?
利用ServletContext對象讀取資源文件
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db1.properties");
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
?
總結
- 上一篇: winform空间批量控制
- 下一篇: bzoj1597[Usaco2008 M