上一篇介紹了在Web項目中web.xml文件的配置信息,本篇主要介紹裡面非常重要的配置——Servlet配置,重點介紹與Servlet相關的幾個介面和類,包括Servlet介面、ServletConfig介面、ServletContext介面、GenericServlet類、HttpServlet類 ...
上一篇介紹了在Web項目中web.xml文件的配置信息,本篇主要介紹裡面非常重要的配置——Servlet配置,重點介紹與Servlet相關的幾個介面和類,包括Servlet介面、ServletConfig介面、ServletContext介面、GenericServlet類、HttpServlet類。
1、Servlet介紹
什麼是Servlet:
百度的解釋是“小服務程式或服務連接器,用Java編寫的伺服器端程式,主要功能在於互動式地瀏覽和修改數據,生成動態Web內容”。Servlet是Java語言裡面的一個介面,任何直接或間接實現了Servlet介面的類都可稱為Servlet類。
Servlet與Tomcat的關係:
Tomcat 是Web應用伺服器,是Servlet的容器。Tomcat 作為Servlet容器,在啟動時可以創建Servlet類的實例,調用init()方法對Servlet進行初始化,同時負責處理客戶請求,把請求傳送給Servlet,並將Servlet的響應傳送回給客戶。可以說,Servlet是一種運行在支持Java語言的伺服器上的組件。在web.xml文件中,通過<servlet>標簽配置Servlet類的相關信息,詳細配置請見 http://www.cnblogs.com/Y-oung/p/8401549.html 。
2、Servlet介面
先看源碼:
package javax.servlet; import java.io.IOException; public abstract interface Servlet { public abstract void init(ServletConfig paramServletConfig) throws ServletException; public abstract ServletConfig getServletConfig(); public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse) throws ServletException, IOException; public abstract String getServletInfo(); public abstract void destroy(); }
init():初始化方法,在Tomcat對Servlet實例化後,Servlet容器會調用init()方法來初始化該對象,讓Servlet對象在處理客戶請求前可以完成一些初始化工作,例如:建立資料庫的連接,獲取配置信息等。在Servlet的整個生命周期中,init()方法自始至終只會被調用一次。init()方法有一個類型為ServletConfig的參數,Servlet容器通過這個參數向Servlet傳遞配置信息。Servlet使用ServletConfig對象從web.xml文件中獲取以名-值對形式提供的初始化參數。另外,在Servlet中,還可以通過ServletConfig對象獲取描述Servlet運行環境的ServletContext對象,使用該對象,Servlet可以和它的Servlet容器進行通信。
如圖中紅圈裡面的配置信息可以在MainServlet類的init()方法裡面解析。
getServletConfig():該方法返回容器調用init()方法時傳遞給Servlet對象的ServletConfig對象,ServletConfig對象包含了Servlet的初始化參數(如上圖紅圈裡的配置信息)。關於ServletConfig介面下麵會介紹。
service():該方法是用來處理客戶端請求(在service()方法被容器調用之前,必須確保init()方法正確完成)的核心方法。容器會構造一個表示客戶端請求信息的請求對象(類型為ServletRequest)和一個用於對客戶端進行響應的響應對象(類型為ServletResponse)作為參數傳遞給service()。在service()方法中,Servlet對象通過ServletRequest對象得到客戶端的相關信息和請求信息,在對請求進行處理後,調用ServletResponse對象的方法設置響應信息。
getServletInfo():該方法返回一個包括了關於Servlet的信息的字元串(如作者、版本和版權等信息),返回的應該是純文本字元串,而不是任何類型的標記。
destroy():該方法用來銷毀Servlet對象。當容器檢測到一個Servlet對象應該從服務中被移除的時候,容器會調用該對象的destroy()方法,以便讓Servlet對象可以釋放它所使用的資源,該方法同樣只會執行一次。當需要釋放記憶體或者容器關閉時,容器就會調用Servlet對象的destroy()方法,在Servlet容器調用destroy()方法前,如果還有其他的線程正在service()方法中執行容器會等待這些線程執行完畢或者等待伺服器設定的超時值到達。一旦Servlet對象的destroy()方法被調用,容器不回再把請求發送給該對象。如果需要改Servlet再次為客戶端服務,容器將會重新產生一個Servlet對象來處理客戶端的請求。在destroy()方法調用之後,容器會釋放這個Servlet對象,在隨後的時間內,該對象會被java的垃圾收集器所回收。
可以看到,Servlet介面裡面只有五個方法:init()、getServletConfig()、service()、getServletInfo()、destroy()。其中init()、service()、destroy()三個方法是和servlet生命周期相關的方法,在生命周期的不同時間段內會執行不同的方法,其順序是init()->service()->destroy()。其中init()、destroy()方法在servlet生命周期中都只執行一次,而service()方法可以多次執行。Servlet介面是Servlet類最底層、最基礎、最重要的介面。
3、ServletConfig介面
先看源碼:
package javax.servlet; import java.util.Enumeration; public abstract interface ServletConfig { public abstract String getServletName(); public abstract ServletContext getServletContext(); public abstract String getInitParameter(String paramString); public abstract Enumeration<String> getInitParameterNames(); }
getServletName():獲取web.xml文件裡面的servlet的名字(即<servlet-name>標簽配置的名字)。
getServletContext():獲取ServletContext對象,下麵會介紹ServletContext介面。
getInitParameter():獲取web.xml文件在servlet標簽中配置的參數值(註意是servlet標簽,而不是其他標簽配置的參數值)。
getInitParameterNames():獲取在Servlet中所有初始化參數的名字,也就是key值,可以通過key值,來找到各個初始化參數的value值(註意返回的是枚舉類型)。
可以看到,ServletConfig介面裡面的方法主要是獲取web.xml文件里和servlet相關的配置信息。
4、ServletContext介面
先看源碼:
package javax.servlet; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Enumeration; import java.util.EventListener; import java.util.Map; import java.util.Set; import javax.servlet.descriptor.JspConfigDescriptor; public abstract interface ServletContext { public static final String TEMPDIR = "javax.servlet.context.tempdir"; public static final String ORDERED_LIBS = "javax.servlet.context.orderedLibs"; public abstract ServletContext getContext(String paramString); public abstract String getContextPath(); public abstract int getMajorVersion(); public abstract int getMinorVersion(); public abstract int getEffectiveMajorVersion(); public abstract int getEffectiveMinorVersion(); public abstract String getMimeType(String paramString); public abstract Set<String> getResourcePaths(String paramString); public abstract URL getResource(String paramString) throws MalformedURLException; public abstract InputStream getResourceAsStream(String paramString); public abstract RequestDispatcher getRequestDispatcher(String paramString); public abstract RequestDispatcher getNamedDispatcher(String paramString); public abstract Servlet getServlet(String paramString) throws ServletException; public abstract Enumeration<Servlet> getServlets(); public abstract Enumeration<String> getServletNames(); public abstract void log(String paramString); public abstract void log(Exception paramException, String paramString); public abstract void log(String paramString, Throwable paramThrowable); public abstract String getRealPath(String paramString); public abstract String getServerInfo(); public abstract String getInitParameter(String paramString); public abstract Enumeration<String> getInitParameterNames(); public abstract boolean setInitParameter(String paramString1, String paramString2); public abstract Object getAttribute(String paramString); public abstract Enumeration<String> getAttributeNames(); public abstract void setAttribute(String paramString, Object paramObject); public abstract void removeAttribute(String paramString); public abstract String getServletContextName(); public abstract ServletRegistration.Dynamic addServlet(String paramString1, String paramString2); public abstract ServletRegistration.Dynamic addServlet(String paramString, Servlet paramServlet); public abstract ServletRegistration.Dynamic addServlet(String paramString, Class<? extends Servlet> paramClass); public abstract <T extends Servlet> T createServlet(Class<T> paramClass) throws ServletException; public abstract ServletRegistration getServletRegistration( String paramString); public abstract Map<String, ? extends ServletRegistration> getServletRegistrations(); public abstract FilterRegistration.Dynamic addFilter(String paramString1, String paramString2); public abstract FilterRegistration.Dynamic addFilter(String paramString, Filter paramFilter); public abstract FilterRegistration.Dynamic addFilter(String paramString, Class<? extends Filter> paramClass); public abstract <T extends Filter> T createFilter(Class<T> paramClass) throws ServletException; public abstract FilterRegistration getFilterRegistration(String paramString); public abstract Map<String, ? extends FilterRegistration> getFilterRegistrations(); public abstract SessionCookieConfig getSessionCookieConfig(); public abstract void setSessionTrackingModes( Set<SessionTrackingMode> paramSet) throws IllegalStateException, IllegalArgumentException; public abstract Set<SessionTrackingMode> getDefaultSessionTrackingModes(); public abstract Set<SessionTrackingMode> getEffectiveSessionTrackingModes(); public abstract void addListener(String paramString); public abstract <T extends EventListener> void addListener(T paramT); public abstract void addListener(Class<? extends EventListener> paramClass); public abstract <T extends EventListener> T createListener( Class<T> paramClass) throws ServletException; public abstract void declareRoles(String[] paramArrayOfString); public abstract ClassLoader getClassLoader(); public abstract JspConfigDescriptor getJspConfigDescriptor(); }
Tomcat為每個web項目都創建一個ServletContext實例,在Tomcat啟動時創建,伺服器關閉時銷毀,在一個web項目中共用數據,管理web項目資源,為整個web配置公共信息等。每一個web項目都存在一個ServletContext實例,每個Servlet都可以訪問它。可以看到,ServletContext介面裡面的方法很多,下麵根據功能介紹其中的方法。
在Web應用範圍記憶體取共用數據的方法:
setAttribute(String paramString, Object paramObject):把一個Java對象與一個屬性名綁定,並把它存入到ServletContext中。paramString參數指定屬性名,paramObject參數標識共用的數據。
getAttribute(String name):根據參數給定的屬性名,返回一個Object類型的對象,它表示ServletContext中與屬性名匹配的屬性值。
getAttributeNames():返回一個Enumeration對象,該對象包含了所有存放在ServletContext中的屬性名。
removeAttribute(String name):根據參數指定的屬性名,從ServletContext中刪除匹配的屬性。
訪問當前Web應用的資源:
getContextPath():返回當前Web應用的URL入口。
getInitParameter(String name):根據給定的參數名,返回Web應用範圍內初始化參數值。在web.xml文件中,直接在<web-app>跟元素下定義的<context-param>元素表示應用範圍內的初始化參數。
getInitParameterNames():返回一個Enumeration對象,它包含了Web應用範圍內的所有初始化參數。
getServletContextName():返回Web應用的名字,即web.xml文件中<display-name>元素的值。
getRequestDispatcher(String path):返回一個用於向其他Web組件轉發請求的RequestDispatcher對象。
訪問Servlet容器中的其他Web應用:
getContext(String uripath):根據參數指定的URI,返回當前Servlet容器中其他Web應用的ServletContext對象。
訪問Servlet容器的相關信息:
getMajorVersion():返回Servlet容器支持的Java Servlet API的主版本號。
getMinorVersion();返回Servlet容器支持的Java Servlet API的次版本號。
getServletInfo():返回Servlet容器的名字和版本。
訪問伺服器端的文件系統資源:
getRealPath(String path):根據參數指定的虛擬路徑,返迴文件系統中的一個真實路徑。
getResource(String path):返回一個映射到參數指定的路徑的URL。
getResourceAsStream(String path):返回一個用於讀取參數指定的文件的輸入流。
getMimeType(String file):返回參數指定的文件的MIME類型。
輸出日誌:
log(String msg)向Servlet的日誌文件中寫日誌。
log(String message , java.lang.Throwable throwable):向Servlet的日誌中寫錯誤日誌,以及異常的堆棧信息。
5、GenericServlet類
先看源碼:
package javax.servlet; import java.io.IOException; import java.io.Serializable; import java.util.Enumeration; public abstract class GenericServlet implements Servlet, ServletConfig, Serializable { private static final long serialVersionUID = 1L; private transient ServletConfig config; public void destroy() { } public String getInitParameter(String name) { return getServletConfig().getInitParameter(name); } public Enumeration<String> getInitParameterNames() { return getServletConfig().getInitParameterNames(); } public ServletConfig getServletConfig() { return this.config; } public ServletContext getServletContext() { return getServletConfig().getServletContext(); } public String getServletInfo() { return ""; } public void init(ServletConfig config) throws ServletException { this.config = config; init(); } public void init() throws ServletException { } public void log(String msg) { getServletContext().log(getServletName() + ": " + msg); } public void log(String message, Throwable t) { getServletContext().log(getServletName() + ": " + message, t); } public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse) throws ServletException, IOException; public String getServletName() { return this.config.getServletName(); } }
可以看到,GenericServlet類是一個抽象的(abstract)類,所以它無法被實例化。它繼承了三個介面,其中Servlet和ServletConfig介面是前面介紹過的,可以看出GenericServlet類裡面大多數方法都是這兩個介面裡面的方法,所以這個類其實是整合了這兩個介面,給出了設計servlet的一些骨架,定義了servlet生命周期,還有一些得到名字、配置、初始化參數的方法,使得編寫servlet類時更方便。GenericServlet類裡面所有繼承了這兩個介面的方法的功能,在本文前面已經詳細介紹,這裡只說明一下這個類裡面新增的方法:log(String msg)、log(String message, Throwable t)、init()。
兩個log()方法:通過ServletContext對象將Servlet的類名和給定的信息寫入log文件中。
兩個init()方法:init(ServletConfig config)方法是實現了Servlet介面中的方法,作用是可以通過getServletConfig()方法獲取ServletConfig對象。如果你覆蓋了這個方法,你必須調用super.init(config),這樣GenericServlet類的其他方法才能正常工作。而它下麵還調用了無參的init()方法,也就是GenericServlet類自定義的無參方法。為什麼還要定義這個無參數的init()方法呢?其實這個無參數的init()方法是專門留給開發者使用的,開發者只需要覆蓋這個方法就可以很方便的在方法裡面擴充一些功能,比如對自己寫的Servlet類初始化時可以在這個方法裡面進行,解析web.xml文件裡面關於servlet配置的信息時可以在這個方法裡面。這樣就不需要覆蓋init(ServletConfig config)方法了,不需要存儲config對象,也不需要調用super.init(config)。
儘管GenericServlet類實現了Servlet和ServletConfig介面的功能,但它的service方法中的參數還是ServletRequest,ServletResponse,它處理的還只一般的Servlet請求,並沒有跟http相關對象掛鉤。service方法是和應用層協議無關的,也就是說你有可能用非http協議實現它。而我們平時通過瀏覽器訪問網站時,基本上都是HTTP請求(當然還有FTP請求),請求方式包括GET、POST等,顯然如果直接使用service方法會很繁瑣,所以提供了一個HttpServlet類來解決這些問題,這個類繼承了GenericServlet類,除了能實現其所有方法,還根據HTTP請求的特性進行了擴充,使得其更能有效地處理基於HTTP協議的請求。
6、HttpServlet類
這個類的源碼有點長,不再詳細展示,有興趣可以去看源碼,這裡通過類的結構圖說明。
其中HTTP協議的請求類型與其對應的實現方法見下表:
該類繼承了GenericServlet類,用於接收基於Http協議的請求,並對請求進行處理,然後做出響應。一般在web開發中,開發者自己編寫的Servlet類只需要繼承HttpServlet類即可。這裡我們重點介紹兩個service()方法。
service(ServletRequest req, ServletResponse res):通過源碼可以發現,此方法是GenericServlet類的service()方法的實現,他把ServletRequest和ServletResponse對象分別強制轉化為HttpServletRequest和HttpServletResponse對象,並把強制轉化後的對象作為參數,調用另一個重載的service(HttpServletRequest req, HttpServletResponse resp)方法。
service(HttpServletRequest req, HttpServletResponse resp):通過源碼可以看出,這個方法會根據不同的HTTP請求類型(GET、POST或其他),調用不同的實現方法(doGet()、doPost()或其他)。這樣一來,當開發者自己編寫Servlet類時(繼承HttpServlet類),我們只需要覆蓋(重寫)doGet()、doPost()或其他doXXX()方法就可以了,而不需要覆蓋(重寫)service()方法,這樣就簡化了許多。實際上筆者在開發中遇到的幾個項目的servlet類中都是覆蓋(重寫)了doGet()、doPost()方法,而沒有覆蓋(重寫)service()方法。
7、總結
本篇著重介紹了和servlet相關的幾個比較重要的介面和類,下麵通過圖片說明它們之間的繼承關係:
在實際的web項目中,如果需要開發者自己寫servlet類,一般直接繼承HttpServlet類即可。在用Tomcat載入servlet類時,如果需要初始化一些信息(比如解析web.xml文件中<servlet>標簽下的配置信息),可以覆蓋(重寫)無參的init()方法;如果要處理GET請求,可以覆蓋(重寫)doGet()方法;如果要處理POST請求,可以覆蓋(重寫)doPost()方法。init()、doGet()、doPost()這三個方法是筆者在開發web項目中遇到最多的,基本上自己寫的servlet類裡面,都是繼承了HttpServlet類,覆蓋(重寫)了這三個方法。
本篇就介紹到這裡了,希望對大家有所幫助。筆者能力有限,裡面難免有不准確或不正確的地方,歡迎各位指正。
轉載請註明出處 http://www.cnblogs.com/Y-oung/p/8419644.html
工作、學習、交流或有任何疑問,請聯繫郵箱:[email protected] 微信:yy1340128046