1. 程式人生 > >servlet3.1規範: 第4章 Servlet上下文(ServletContext)

servlet3.1規範: 第4章 Servlet上下文(ServletContext)

Servlet上下文

4.1 ServletContext介面介紹

ServletContext(Servlet上下文)介面定義了servlet執行在的Web應用的檢視。容器供應商負責提供Servlet容器的ServletContext介面的實現。Servlet可以使用ServletContext物件記錄事件,獲取URL引用的資源,存取當前上下文的其他Servlet可以訪問的屬性。

ServletContext是Web伺服器中已知路徑的根。例如,Servlet上下文可以從http://www.mycorp.com/catalog找出,/catalog請求路徑稱為上下文路徑,所有以它開頭的請求都會被路由到與ServletContext 相關聯的Web應用。

4.2 ServletContext介面作用範圍

每一個部署到容器的Web應用都有一個Servlet介面的例項與之關聯。在容器分佈在多臺虛擬機器的情況下,每個JVM的每個Web應用將有一個ServletContext例項。

如果容器內的Servlet沒有部署到Web應用中,則隱含的作為”預設”Web應用的一部分,並有一個預設的ServletContext。在分散式的容器中,預設的ServletContext是非分散式的且僅存在於一個JVM中。

4.3 初始化引數

如下ServletContext介面方法允許Servlet訪問由應用開發人員在Web應用中的部署描述符中指定的上下文初始化引數:

■getInitParameter
■getInitParameterNames

應用開發人員使用初始化引數來表達配置資訊。代表性的例子是一個Webmaster的e-mail地址,或儲存關鍵資料的系統名稱。

4.4 配置方法

下面的方法從Servlet3.0開始新增到ServletContext,以便啟用程式設計方式定義Servlet、Filter和它們對映到的url模式(url pattern)。這些方法只能從ServletContextListener實現的contexInitialized方法或者ServletContainerInitializer實現的onStartup方法進行的應用初始化過程中呼叫。 除了新增Servlet和Filter,也可以查詢關聯到Servlet或Filter的一個Registration物件例項,或者到Servlet或Filter的所有Registration物件的map。

如果ServletContext傳到了ServletContextListener的contextInitialized方法,但該ServletContextListener即沒有在web.xml或web-fragment.xml中宣告也沒有使用@WebListener註解,則在ServletContext中定義的用於Servlet、Filter和Listener的程式設計式配置的所有方法必須丟擲UnsupportedOperationException。

4.4.1 程式設計式新增和配置Servlet

程式設計式新增Servlet到上下文對框架開發者是很有用的。例如,框架可以使用這個方法宣告一個控制器Servlet。這個方法將返回一個ServletRegistration或ServletRegistration.Dynamic物件,允許我們進一步配置如init-params,url-mapping等Servlet的其他引數。下面描述了該方法的三個過載版本。

4.4.1.1addServlet(String servletName, String className)

該方法允許應用以程式設計方式宣告一個Servlet。它新增以給定的名稱和class名稱的Servlet到servlet上下文。

4.4.1.2addServlet(String servletName, Servlet servlet)

該方法允許應用以程式設計方式宣告一個Servlet。它新增以給定的名稱和Servlet例項的Servlet到servlet上下文。

4.4.1.3addServlet(String servletName, Class <? extends Servlet> servletClass)

該方法允許應用以程式設計方式宣告一個Servlet。它新增以給定的名稱和Servlet類的一個例項的Servlet到servlet上下文。

4.4.1.4<T extends Servlet> T createServlet(Class<T> clazz)

該方法例項化一個給定的Servletclass,該方法必須支援適用於Servlet的除了@WebServlet的所有註解。

返回的Servlet例項通過呼叫上邊定義的addServlet(String,Servlet)註冊到ServletContext之前,可以進行進一步的定製。

4.4.1.5ServletRegistration getServletRegistration(String servletName)

該方法返回與指定名字的Servlet相關的ServletRegistration,或者如果沒有該名字的ServletRegistration則返回null。如果ServletContext傳到了ServletContextListener的contextInitialized方法,但該ServletContextListener即沒有在web.xml或web-fragment.xml中宣告也沒有使用javax.servlet.annotation.WebListener註解,則必須丟擲UnsupportedOperationException。

4.4.1.6Map<String, ? extends ServletRegistration> getServletRegistrations()

該方法返回ServletRegistration物件的map,由名稱作為鍵並對應著註冊到ServletContext的所有Servlet。如果沒有Servlet註冊到ServletContext則返回一個空的map。返回的Map包括所有宣告和註解的Servlet對應的ServletRegistration物件,也包括那些使用addServlet方法新增的所有Servlet對於的ServletRegistration物件。返回的Map的任何改變不影響ServletContext。如果ServletContext傳到了ServletContextListener的contextInitialized方法,但該ServletContextListener即沒有在web.xml或web-fragment.xml中宣告也沒有使用javax.servlet.annotation.WebListener註解,則必須丟擲UnsupportedOperationException。

4.4.2 程式設計式新增和配置Filter

4.4.2.1addFilter(String filterName, String className)

該方法允許應用以程式設計方式宣告一個Filter。它新增以給定的名稱和class名稱的Filter到web應用。

4.4.2.2addFilter(String filterName, Filter filter)

該方法允許應用以程式設計方式宣告一個Filter。它新增以給定的名稱和filter例項的Filter到web應用。

4.4.2.3addFilter(String filterName, Class <? extends Filter> filterClass)

該方法允許應用以程式設計方式宣告一個Filter。它新增以給定的名稱和filter類的一個例項的Filter到web應用。

4.4.2.4<T extends Filter> T createFilter(Class<T> clazz)

該方法例項化一個給定的Filterclass,該方法必須支援適用於Filter的所有註解。

返回的Filter例項通過呼叫上邊定義的addServlet(String, Filter)註冊到ServletContext之前,可以進行進一步的定製。給定的Filter類必須定義一個用於例項化的空參構造器。

4.4.2.5FilterRegistration getFilterRegistration(String filterName)

該方法返回與指定名字的Filter相關的FilterRegistration,或者如果沒有該名字的FilterRegistration則返回null。如果ServletContext傳到了ServletContextListener的contextInitialized方法,但該ServletContextListener即沒有在web.xml或web-fragment.xml中宣告也沒有使用javax.servlet.annotation.WebListener註解,則必須丟擲UnsupportedOperationException。

4.4.2.6Map<String, ? extends FilterRegistration> getFilterRegistrations()

該方法返回FilterRegistration物件的map,由名稱作為鍵並對應著註冊到ServletContext的所有Filter。如果沒有Filter註冊到ServletContext則返回一個空的map。返回的Map包括所有宣告和註解的Filter對應的FilterRegistration物件,也包括那些使用addFilter方法新增的所有Servlet對於的ServletRegistration物件。返回的Map的任何改變不影響ServletContext。如果ServletContext傳到了ServletContextListener的contextInitialized方法,但該ServletContextListener即沒有在web.xml或web-fragment.xml中宣告也沒有使用javax.servlet.annotation.WebListener註解,則必須丟擲UnsupportedOperationException。

4.4.3程式設計式新增和配置Listener

4.4.3.1void addListener(String className)

往ServletContext新增指定class名稱的監聽器。ServletContext將使用由與應用關聯的classloader裝載載入該給定名稱的class,且它們必須實現一個或多個以下介面:

■javax.servlet.ServletContextAttributeListener
■javax.servlet.ServletRequestListener
■javax.servlet.ServletRequestAttributeListener
■javax.servlet.http.HttpSessionListener
■javax.servlet.http.HttpSessionAttributeListener

如果ServletContext傳到了ServletContainerInitializer的onStartup方法,則給定名字的類可以實現除上面列出的介面之外的javax.servlet.ServletContextListener。作為該方法呼叫的一部分,容器必須裝載指定類名的class,以確保其實現了所需的介面之一。如果給定名字的類實現了一個監聽器介面,則其呼叫順序和宣告順序是一樣的,換句話說,如果它實現了javax.servlet.ServletRequestListener 或 javax.servlet.http.HttpSessionListener,那麼新的監聽器將被新增到該介面的有序監聽器列表的末尾。

4.4.3.2<T extends EventListener> void addListener(T t)

往ServletContext新增一個給定的監聽器。給定的監聽器例項必須實現是一個或多個如下介面:

■javax.servlet.ServletContextAttributeListener
■javax.servlet.ServletRequestListener
■javax.servlet.ServletRequestAttributeListener
■javax.servlet.http.HttpSessionListener
■javax.servlet.http.HttpSessionAttributeListener

如果ServletContext傳到了ServletContainerInitializer的onStartup方法,則給定的監聽器例項可以實現除上面列出的介面之外的javax.servlet.ServletContextListener。如果給定的監聽器例項實現了一個監聽器介面,則其呼叫順序和宣告順序是一樣的,換句話說,如果它實現了javax.servlet.ServletRequestListener 或 javax.servlet.http.HttpSessionListener,那麼新的監聽器將被新增到該介面的有序監聽器列表的末尾。

4.4.3.3void addListener(Class <? extends EventListener> listenerClass)

往ServletContext新增指定class型別的監聽器。給定的監聽器類必須實現是一個或多個如下介面:

■javax.servlet.ServletContextAttributeListener
■javax.servlet.ServletRequestListener
■javax.servlet.ServletRequestAttributeListener
■ javax.servlet.http.HttpSessionListener
■javax.servlet.http.HttpSessionAttributeListener

如果ServletContext傳到了ServletContainerInitializer的onStartup方法,則給定的監聽器類可以實現除上面列出的介面之外的javax.servlet.ServletContextListener。如果給定的監聽器類實現了一個監聽器介面,則其呼叫順序和宣告順序是一樣的,換句話說,如果它實現了javax.servlet.ServletRequestListener 或 javax.servlet.http.HttpSessionListener,那麼新的監聽器將被新增到該介面的有序監聽器列表的末尾。

4.4.3.4<T extends EventListener> void createListener(Class<T> clazz)

該方法例項化給定的EventListener類。指定的EventListener類必須實現至少一個如下介面:

■javax.servlet.ServletContextAttributeListener
■javax.servlet.ServletRequestListener
■javax.servlet.ServletRequestAttributeListener
■javax.servlet.http.HttpSessionListener
■javax.servlet.http.HttpSessionAttributeListener

該方法必須支援該規範定義的適用於如上介面的所有註解。返回的EventListener例項可以在通過呼叫addListener(T t)註冊到ServletContext之前進行進一步的定製。給定的EventListener必須定義一個用於例項化的空參構造器。

4.4.3.5用於程式設計式新增Servlet、Filter和Listener的註解處理需求

當時有程式設計式API新增Servlet或建立Servlet時,apart from the addServlet thattakes an instance,下面的註解必須被內省
When using the programmatic API to add aservlet or create a servlet, apart from the addServlet that takes an instance,the following annotations must be introspected in the class in question and themetadata defined in it MUST be used unless it is overridden by calls to the APIin the ServletRegistration.Dynamic /

ServletRegistration.

@ServletSecurity, @RunAs, @DeclareRoles,@MultipartConfig.
Filter和Listener不需要內省註解。

除了那些使用帶有一個例項的方法新增的元件,在程式設計式新增或建立的所有元件(Servlet,Filter和Listener)上的資源注入,只有當元件是一個Managed Bean時才被支援。Managed Bean的更多細節請參考JavaEE6部分和JSR299中定義的Managed Bean規範。

4.5 上下文屬性

Servlet可以使用指定的名字將物件屬性繫結到上下文。同一個Web應用內的其他任何Servlet都可以使用繫結到上下文的任意屬性。以下Servlet介面中的方法允許訪問此功能:

■ setAttribute
■ getAttribute
■getAttributeNames
■removeAttribute

4.5.1分散式容器中的上下文屬性

在JVM中建立的上下文屬性是本地的,這可以防止從一個分散式容器的共享記憶體儲存中獲取ServletContext屬性。當需要在執行在分散式環境的Servlet之間共享資訊時,該資訊應該被放到session(請看第7章,”會話”),或儲存到資料庫,或者設定到企業級JavaBean元件(Enterprise JavaBeans™)。

4.6 資源

ServletContext介面提供了直接訪問Web應用中靜態內容層次結構的檔案的方法,包括HTML,GIF和JPEG檔案:

■ getResource
■getResourceAsStream

getResource和getResourceAsStream方法需要一個以“/”開頭的String字串作為引數,給定的資源路徑是相對於上下文的根,或者相對於web應用的WEB-INF/lib目錄下的JAR檔案中的META-INF/resources目錄。這兩個方法首先根據請求的資源查詢web應用上下文的根,然後查詢所有WEB-INF/lib目錄下的JAR檔案。查詢WEB-INF/lib目錄中JAR檔案的順序是不確定的。這種層次結構的檔案可以存在於伺服器的檔案系統,Web應用的歸檔檔案,遠端伺服器,或在其他位置。

這兩個方法不能用於獲取動態內容。例如,在支援JavaServer Pages™規範(JavaServer Pages™ 規範可以在http://java.sun.com/products/jsp找到)的容器中,如getResource(“/index.jsp”)形式的方法呼叫將返回JSP原始碼而不是處理後的輸出。請看第9章,“分派請求”獲取更多關於動態內容的資訊。

可以使用getResourcePaths(Stringpath)方法訪問Web應用中的資源的完整列表。該方法的語義的全部細節可以從本規範的API文件中找到。

4.7 多主機和Servlet上下文

Web伺服器可以支援多個邏輯主機共享一個伺服器IP地址。有時,這種能力被稱為“虛擬主機”。這種情況下,每一個邏輯主機必須有它自己的上下文或一組上下文。Servlet上下文不會在虛擬主機之間共享。

4.8 Reload注意事項

儘管容器供應商不需要實現類的重新載入(reload)模式以便易於開發,但是任何此類的實現必須確保所有servlet及它們使用的類(Servlet使用的系統類異常可能使用的是一個不同的class loader)在一個單獨的class loader範圍內被載入。為了保證應用像開發人員預期的那樣工作,該要求是必須的。作為一個開發輔助,容器應支援到session繫結到的監聽器的完整通知語義以用於當class重新載入時session終結的監控。

之前幾代的容器建立新的class loader來載入servlet,且與用於載入在servlet上下文中使用的其他Servlet或類的class loader是完全不同的。這可能導致servlet上下文中的物件引用指向意想不到的類或物件,並引起意想不到的行為。為了防止因建立新的class loader所引起的問題,該要求是必須的。

4.8.1 臨時工作目錄

每一個servlet上下文都需要一個臨時的儲存目錄。Servlet容器必須為每一個servlet上下文提供一個私有的臨時目錄,並將通過javax.servlet.context.tempdir上下文屬性使其可用,關聯該屬性的物件必須是java.io.File型別。該要求公認為在多個servlet引擎實現中提供一個通用的便利。當servlet容器重啟時,它不需要去保持臨時目錄中的內容,但必須確保一個servlet上下文的臨時目錄中的內容對執行在同一個servlet容器的其他Web應用的上下文不可見。