亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Servlet3.1規范翻譯——Servlet接口

系統 1796 0

補發之前遺漏的一章,pdf版的沒問題,下載地址: http://jinnianshilongnian.iteye.com/admin/blogs/1775987

?

Servlet接口是Java Servlet API的核心抽象。所有Servlet類必須直接或間接的實現該接口,或者更通常做法是通過繼承一個實現了該接口的類從而復用許多共性功能。目前有GenericServlet和HttpServlet這兩個類實現了Servlet接口。大多數情況下,開發者只需要繼承HttpServlet去實現自己的Servlet即可。

?

2.1 請求處理方法

Servlet基礎接口定義了用于客戶端請求處理的service方法。當有請求到達時,該方法由servlet容器路由到一個servlet實例。

Web應用程序的并發請求處理通常需要Web開發人員去設計適合多線程執行的Servlet,從而保證service方法能在一個特定時間點處理多線程并發執行。(注:即Servlet默認是線程不安全的,需要開發人員處理多線程問題)

通常Web容器對于并發請求將使用同一個servlet處理,并且在不同的線程中并發執行service方法。

?

2.1.1 基于Http規范的請求處理方法

HttpServlet抽象子類在Servlet接口基礎之上添加了些協議相關的方法,并且這些方法能根據HTTP請求類型自動的由HttpServlet中實現的service方法轉發到相應的協議相關的處理方法上。這些方法是:

■ doGet處理HTTP GET請求

■ doPost處理HTTP POST請求

■ doPut處理HTTP PUT請求

■ doDelete處理HTTP DELETE請求

■ doHead處理HTTP HEAD請求

■ doOptions處理HTTP OPTIONS請求

■ doTrace處理HTTP TRACE請求

一般情況下,當開發基于HTTP協議的Servlet時,Servlet開發人員將僅去實現doGet 和 doPost請求處理方法即可。如果開發人員想使用其他處理方法,其使用方式跟之前的是類似的,即HTTP編程都是類似。

?

2.1.2 附加的方法

doPut和doDelete方法允許Servlet開發人員讓支持HTTP/1.1的客戶端使用這些功能。HttpServlet中的doHead方法可以認為是doGet方法的一個特殊形式,它僅返回由doGet方法產生的header信息。doOptions方法返回當前servlet支持的HTTP方法(譯者注:通過Allow響應頭返回支持的HTTP操作,如GET、POST)。doTrace方法返回的響應包含TRACE請求的所有頭信息。

?

2.1.3 有條件GET支持

HttpServlet定義了用于支持有條件GET操作的getLastModified方法。所謂的有條件GET操作是指客戶端通過GET請求獲取資源時,當資源自第一次獲取那個時間點發生更改后才再次發生數據,否則將使用客戶端緩存的數據。在一些適當的場合,實現此方法可以更有效的利用網絡資源,減少不必要的數據發送。

?

2.2 實例數量

通過注解描述的(第8章 注解和可插拔性)或者在Web應用程序的部署描述符(第14章 部署描述符)中描述的servlet聲明,控制著servlet容器如何提供servlet實例。

對于未托管在分布式環境中(默認)的servlet而言,servlet容器對于每一個Servlet聲明必須且只能產生一個實例。不過,如果Servlet實現了SingleThreadModel接口,servlet容器可以選擇實例化多個實例以便處理高負荷請求或者串行化請求到一個特定實例。

如果servlet以分布式方式進行部署,容器可以為每個虛擬機(JVM)的每個Servlet聲明產生一個實例。但是,如果在分布式環境中servlet實現了SingleThreadModel接口,此時容器可以為每個容器的JVM實例化多個Servlet實例。

?

2.2.1 關于 Single Thread Model

SingleThreadModel 接口的作用是保證一個特定servlet實例的service方法在一個時刻僅能被一個線程執行,一定要注意,此保證僅適用于每一個servlet實例,因此容器可以選擇池化這些對象。有些對象可以在同一時刻被多個servlet實例訪問,如HttpSession實例,可以在一個特定的時間對多個Servlet可用,包括那些實現了SingleThreadModel接口的Servlet。

?

2.3 Servlet生命周期

Servlet是按照一個嚴格定義的生命周期被管理,該生命周期規定了Servlet如何被加載、實例化、初始化、處理客戶端請求,以及何時結束服務。該聲明周期可以通過javax.servlet.Servlet 接口中的init、service和destroy這些API來表示,所有Servlet必須直接或間接的實現GenericServlet或HttpServlet抽象類。

?

2.3.1 加載和實例化

Servlet容器負責加載和實例化Servlet。加載和實例化可以發生在容器啟動時,或者延遲初始化直到容器決定有請求需要處理時。當Servlet引擎啟動后,servlet容器必須定位所需要的Servlet類。Servlet容器使用普通的Java類加載設施加載Servlet類??梢詮谋镜匚募到y或遠程文件系統或者其他網絡服務加載。加載完Servlet類后,容器就可以實例化它并使用了。

?

2.3.2 初始化

一旦一個Servlet對象實例化完畢,容器接下來必須在處理客戶端請求之前初始化該Servlet實例。初始化的目的是以便Servlet能讀取持久化配置數據,初始化一些代價高的資源(比如JDBC API 連接),或者執行一些一次性的動作。容器通過調用Servlet實例的init方法完成初始化,init方法定義在Servlet接口中,并且提供一個唯一的ServletConfig接口實現的對象作為參數,該對象每個Servlet實例一個。

配置對象允許Servlet訪問由Web應用配置信息提供的鍵-值對的初始化參數。該配置對象也提供給Servlet去訪問一個ServletContext對象,ServletContext描述了Servlet的運行時環境。請參考第4章,“Servlet Context”獲取ServletContext接口的更多信息。

?

2.3.2.1 初始化時的錯誤條件

在初始化階段,servlet實現可能拋出UnavailableException或ServletException異常。在這種情況下,Servlet不能放置到活動服務中,而且Servlet容器必須釋放它。如果初始化沒有成功,destroy方法不應該被調用。

在實例初始化失敗后容器可能再實例化和初始化一個新的實例。此規則的例外是,當拋出的UnavailableException表示一個不可用的最小時間,容器在創建和初始化一個新的servlet實例之前必須等待一段時間。

2.3.2.2使用工具時的注意事項

當一個工具加載并內省某個Web應用程序時觸發的靜態初始化,這種用法與調用init初始化方法是有區別的。在Servlet的init方法沒被調用,開發人員不應該假定其處于活動的容器環境內。比如,當某個Servlet僅有靜態方法被調用時,不應該與數據庫或企業級JavaBean(EJB)容器建立連接。

?

2.3.3 請求處理

Servlet完成初始化后,Servlet容器就可以使用它處理客戶端請求了。客戶端請求由ServletRequest類型的request對象表示。Servlet封裝響應并返回給請求的客戶端,該響應由ServletResponse類型的response對象表示。這兩個對象(request和response)是由容器通過參數傳遞到Servlet接口的service方法的。

在HTTP請求的場景下,容器提供的請求和響應對象具體類型分別是HttpServletRequest 和 HttpServletResponse。

需要注意的是,由Servlet容器初始化的某個Servlet 實例在服務期間,可以在其生命周期中不處理任何請求。

?

2.3.3.1 多線程問題

Servlet容器可以并發的發送多個請求到Servlet的service方法。為了處理這些請求,Servlet開發者必須為service方法的多線程并發處理做好充足的準備。一個替代的方案是開發人員實現SingleThreadModel接口,由容器保證一個service方法在同一個時間點僅被一個請求線程調用,但是此方案是不推薦的。Servlet容器可以通過串行化訪問Servlet的請求,或者維護一個Servlet實例池完成該需求。如果Web應用中的Servlet被標注為分布式的,容器應該為每一個分布式應用程序的JVM維護一個Servlet實例池。

對于那些沒有實現SingleThreadModel 接口的Servlet,但是它的service方法(或者是那些HttpServlet中通過service方法分派的doGet、doPost等分派方法)是通過synchronized關鍵詞定義的,Servlet容器不能使用實例池方案,并且只能使用序列化請求進行處理。強烈推薦開發人員不要去通過service方法(或者那些由Service分派的方法),因為這將嚴重影響性能。

?

2.3.3.2 請求處理時的異常

Servlet在處理一個請求時可能拋出ServletException或UnavailableException異常。ServletException表示在處理請求時出現了一些錯誤,容器應該采取適當的措施清理掉這個請求。

UnavailableException表示servlet目前無法處理請求,或者臨時性的或者永久性的。

如果UnavailableException表示的是一個永久性的不可用,Servlet容器必須從服務中移除這個Servlet,調用它的destroy方法,并釋放Servlet實例。所有被容器拒絕的請求,都會返回一個SC_NOT_FOUND (404) 響應。

如果UnavailableException表示的是一個臨時性的不可用,容器可以選擇在臨時不可用的這段時間內路由任何請求到Servlet。所以在這段時間內被容器拒絕的請求,都會返回一個SC_SERVICE_UNAVAILABLE (503)響應狀態碼,且同時會返回一個Retry-After頭指示此Servlet什么時候可用。容器可以選擇忽略永久性和臨時性不可用的區別,并把UnavailableExceptions視為永久性的,從而Servlet拋出UnavailableException后需要把它從服務中移除。

?

2.3.3.3 異步處理

有時候,Filter及/或 Servlet在生成響應之前必須等待一些資源或事件以便完成請求處理。比如,Servlet在進行生成一個響應之前可能等待一個可用的JDBC連接,或者一個遠程web服務的響應,或者一個JMS消息,或者一個應用程序事件。在Servlet中等待是一個低效的操作,因為這是阻塞操作,從而白白占用一個線程或其他一些受限資源。許多線程為了等待一個緩慢的資源比如數據庫經常發生阻塞,可能引起線程饑餓,且降低整個Web容器的服務質量。當

Servlet 3.0引入了異步處理請求的能力,使線程可以返回到容器,從而執行更多的任務。當開始異步處理請求時,另一個線程或回調可以或者產生響應,或者調用完成(complete)或請求分派(dispatch),這樣,它可以在容器上下文使用AsyncContext.dispatch方法運行。一個典型的異步處理事件順序是:

1. 請求被接收到,通過一系列如用于驗證的等標準的filter之后被傳遞到Servlet。

2. servlet處理請求參數及(或)內容體從而確定請求的類型。

3. 該servlet發出請求去獲取一些資源或數據,例如,發送一個遠程web服務請求或加入一個等待JDBC連接的隊列。

4. servlet不產生響應并返回。

5. 過了一段時間后,所請求的資源變為可用,此時處理線程繼續處理事件,要么在同一個線程,要么通過AsyncContext分派到容器中的一個資源上。

?

Java企業版的功能,如第15.2.2節,在第15-178頁的“Web應用環境”和第15.3.1節,在第15-180頁的“EJB調用的安全標識傳播”,僅提初始化請求的線程執行,或者請求經過AsyncContext.dispatch方法被分派到容器。Java企業版的功能可能支持由AsyncContext.start(Runnable)方法使用其他線程直接操作響應對象。

第八章描述的@WebServlet和@WebFilter注解有一個屬性——asyncSupported,boolean類型默認值為false。當asyncSupported設置為true,應用通過執行startAsync(見下文)可以啟動一個單獨的線程中進行異步處理,并把請求和響應的引用傳遞給這個線程,然后退出原始線程所在的容器。這意味著響應將遍歷(相反的順序)與進入時相同的過濾器(或過濾器鏈)。直到AsyncContext調用complete(見下文)時響應才會被提交。如果異步任務在容器啟動的分派之前執行,且調用了startAsync并返回給容器,此時應用需負責處理請求和響應對象的并發訪問。

從一個Servlet分派時,把asyncSupported=true設置為false是允許的。這種情況下,當servlet的service方法不支持異步退出時,響應將被提交,且容器負責調用AsyncContext的complete,以便所有感興趣的AsyncListener得到觸發知。過濾器作為清理要完成的異步任務持有的資源的一種機制,也應該使用AsyncListener. onComplete觸發的結果。

從一個同步Servlet分派到另一個異步Servlet是非法的。不過與該點不同的是當應用調用startAsync時將拋出IllegalStateException。這將允許servlet只能作為同步的或異步的Servlet。

應用在一個與初始請求所用的不同的線程中等待異步任務直到可以直接寫響應,這個線程不知道任何過濾器。如果過濾器想處理新線程中的響應,那就必須在處理進入時的初始請求時包裝response,并且把包裝的response傳遞給鏈中的下一個過濾器,并最終交給Servlet。因此,如果響應是包裝的(可能被包裝多次,每一個過濾器一次),并且應用處理請求并直接寫響應,這將只寫響應的包裝對象,即任何輸出的響應都會由響應的包裝對象處理。當應用在一個單獨的線程中讀請求時,寫內容到響應的包裝對象,這其實是從請求的包裝對象讀取,并寫到響應的包裝對象,因此對包裝對象操作的所有輸入及(或)輸出將繼續存在。

?

如果應用選擇這樣做的話,它將可以使用AsyncContext從一個新線程發起到容器資源的分派請求。這將允許在容器范圍內使用像JSP這種內容生成技術。

?

除了注解屬性外,我們還添加了如下方法/類:

ServletRequest

■ public AsyncContext startAsync(ServletRequest req, ServletResponse res)。這個方法的作用是將請求轉換為異步模式,并使用給定的請求及響應對象和getAsyncTimeout返回的超時時間初始化它的AsyncContext。ServletRequest和ServletResponse參數必須是與傳遞給servlet的service或filter的doFilter方法相同的對象,或者是ServletRequestWrapper和ServletResponseWrapper子類的包裝對象。當應用退出service方法時,調用該方法必須確保response沒有被提交。當調用返回的AsyncContext的AsyncContext.complete或AsyncContext超時并且沒有監聽器處理超時時,它將被提交。異步超時定時器直到請求和它關聯的響應從容器返回時才啟動。AsyncContext可以被異步線程用來寫響應,它也能用來通知沒有關閉和提交的響應。

如果請求在不支持異步操作的servlet或filter范圍中調用startAsync,或者響應已經被提交或關閉,或者在同一個分派期間重復調用,這些是非法的。從調用startAsync返回的AsyncContext可以接著被用來進行進一步的異步處理。調用返回的AsyncContext 的hasOriginalRequestResponse()方法將返回false,除非傳過去的ServletRequest和ServletResponse參數是最原始的那個或不是應用提供的包裝器。

在請求設置為異步模式后,在入站調用期間添加的一些請求及(或)響應的包裝器可能需要在異步操作期間一直保持,并且它們關聯的資源可能也不會釋放,出站方向調用的所有過濾器可以以此作為一個標志。

一個在入站調用期間的過濾器應用的ServletRequestWrapper可以被出站調用的過濾器釋放,只有當給定的ServletRequest是由AsyncContext初始化的且通過調用AsyncContext.getRequest()返回的,不包括之前說的ServletRequestWrapper。這規則同樣適用于ServletResponseWrapper實例。

?

■ public AsyncContext startAsync() 是一個簡便方法,使用原始請求和響應對象用于異步處理。請注意,如果它們在你想調用此方法之前被包裝了,這個方法的使用者應該刷出(flush)響應,確保數據寫到被包裝的響應中沒有丟失。

?

■ public AsyncContext getAsyncContext() – 返回由startAsync 調用創建的或初始化的AsyncContext。如果請求已經被設置為異步模式,調用getAsyncContext 是非法的。

?

■ public boolean isAsyncSupported() – 如果請求支持異常處理則返回true,否則返回false。一旦請求傳給了過濾器或servlet不支持異步處理(通過指定的注解或聲明),異步支持將被禁用。

?

■ public boolean isAsyncStarted() – 如果請求的異步處理已經開始將返回true,否則返回false。如果這個請求自從被設置為異步模式后已經使用任意一個AsyncContext.dispatch方法分派,或者成功調用了AsynContext.complete 方法,這個方法將返回false。

?

■ public DispatcherType getDispatcherType() – 返回請求的分派器(dispatcher)類型。容器使用請求的分派器類型來選擇需要應用到請求的過濾器。只有匹配分派器類型和url模式(url pattern)的過濾器才會被應用。允許一個過濾器配置多個分派器類型,過濾器可以根據請求的不同分派器類型處理請求。請求的初始分派器類型定義為DispatcherType.REQUEST 。使用RequestDispatcher.forward(ServletRequest, ServletResponse) 或 RequestDispatcher.include(ServletRequest, ServletResponse) 分派時,它們的請求的分派器類型分別是DispatcherType.FORWARD 或 DispatcherType.INCLUDE ,當一個異步請求使用任意一個AsyncContext.dispatch方法分派時該請求的分派器類型是DispatcherType.ASYNC。最后,由容器的錯誤處理機制分派到錯誤頁面的分派器類型是DispatcherType.ERROR 。

?

AsyncContext – 該類表示在ServletRequest啟動的異步操作執行上下文,AsyncContext由之前描述的ServletRequest.startAsync創建并初始化。AsyncContext 的方法:

■ public ServletRequest getRequest() – 返回調用startAsync用于初始化AsyncContext 的請求對象。當在異步周期之前調用了complete或任意一個dispatch方法,調用getRequest將拋出IllegalStateException。???

?

■ public ServletResponse getResponse() –返回調用startAsync用于初始化AsyncContext 的響應對象。當在異步周期之前調用了complete或任意一個dispatch方法,調用getResponse將拋出IllegalStateException。???

?

■ public void setTimeout(long timeoutMilliseconds) – 設置異步處理的超時時間,以毫秒為單位。該方法調用將覆蓋容器設置的超時時間。如果沒有調用setTimeout 設置超時時間,將使用容器默認的超時時間。一個小于等于0的數表示異步操作將永不超時。當調用任意一個ServletRequest.startAsync方法時,一旦容器啟動的分派返回到容器,超時時間將應用到AsyncContext。當在異步周期開始時容器啟動的分派已經返回到容器后,再設置超時時間是非法的,這將拋出一個IllegalStateException異常。

?

■ public long getTimeout() – 獲取AsyncContext關聯的超時時間的毫秒值。該方法返回容器默認的超時時間,或最近一次調用setTimeout設置超時時間。

?

■ public void addListener(AsyncListener listener, ServletRequest req, ServletResponse res) – 注冊一個用于接收的onTimeout, onError, onComplete 或 onStartAsync通知的監聽器。前三個是與最近通過調用任意ServletRequest.startAsync方法啟動的異步周期相關聯的。onStartAsync 是與通過任意ServletRequest.startAsync 啟動的一個新的異步周期相關聯的。異步監聽器將以它們添加到請求時的順序得到通知。當AsyncListener得到通知,傳入到該方法的請求響應對象與AsyncEvent.getSuppliedRequest()和AsyncEvent.getSuppliedResponse()是完全相同的。不應該對這些對象進行讀取或寫入,因為自從注冊了AsyncListener后可能發生了額外的包裝,不過可以被用來按順序釋放與它們關聯的資源。容器啟動的分派在異步周期啟動后返回到容器后,或者在一個新的異步周期啟動之前,調用該方法是非法的,將拋出IllegalStateException。

?

■ public <T extends AsyncListener> createListener(Class<T> clazz) – 實例化指定的AsyncListener類。返回的AsyncListener實例在使用下文描述的addListener方法注冊到AsyncContext之前可能需要進一步的自定義。給定的AsyncListener類必須定義一個用于實例化的空參構造器,該方法支持適用于AsyncListener的所有注解。

?

■ public void addListener(AsyncListener) – 注冊給定的監聽器用于接收onTimeout, onError, onComplete 或 onStartAsync通知。前三個是與最近通過調用任意ServletRequest.startAsync方法啟動的異步周期相關聯的。onStartAsync 是與通過任意ServletRequest.startAsync 啟動的一個新的異步周期相關聯的。異步監聽器將以它們添加到請求時的順序得到通知。當AsyncListener接收到通知,如果在請求時調用startAsync(req, res) 或startAsync(),從AsyncEvent會得到同樣的請求和響應對象。請求和響應對象可以是或者不是被包裝的。異步監聽器將以它們添加到請求時的順序得到通知。容器啟動的分派在異步周期啟動后返回到容器后,或者在一個新的異步周期啟動之前,調用該方法是非法的,將拋出IllegalStateException。

?

■ public void dispatch(String path) – 將用于初始化AsyncContext的請求和響應分派到指定的路徑的資源。該路徑以相對于初始化AsyncContext 的ServletContext進行解析。與請求查詢方法相關的所有路徑,必須反映出分派的目標,同時原始請求的URI,上下文,路徑信息和查詢字符串都可以從請求屬性中獲取,請求屬性定義在9-98頁的9.7.2章節,“分派的請求參數”。這些屬性必須反映最原始的路徑元素,即使在多次分派之后。

?

■ public void dispatch() – 一個簡便方法,使用初始化AsyncContext 時的請求和響應進行分派,如下所示。 如果使用startAsync(ServletRequest, ServletResponse)初始化AsyncContext,且傳入的請求是HttpServletRequest的一個實例,則使用HttpServletRequest.getRequestURI()返回的URI進行分派。否則分派的是容器最后分派的請求URI。下面的代碼示例2-1,代碼示例2-2和代碼示例2-3演示了不同情況下分派的目標URI是什么。

代碼示例2-1:

      // 請求到 /url/A
AsyncContext ac = request.startAsync();
...
ac.dispatch(); // 異步分派到 /url/A
    

???

代碼示例 2-2 :

      // 請求到 /url/A
// 轉發到 /url/B
request.getRequestDispatcher(“/url/B”).forward(request, response);
// 從FORWARD的目標內啟動異步操作
AsyncContext ac = request.startAsync();
ac.dispatch(); // 異步分派到 /url/A
 
    

?

代碼示例2-3:

      // 請求到 /url/A
// 轉發到 /url/B
request.getRequestDispatcher(“/url/B”).forward(request, response);
// 從FORWARD的目標內啟動異步操作
AsyncContext ac = request.startAsync(request, response);
ac.dispatch(); //異步分派到 /url/B
    

??

?

■ public void dispatch(ServletContext context, String path) -將用于初始化AsyncContext的請求和響應分派到指定ServletContext的指定路徑的資源。

?

■ 之上定義了dispatch 方法的全部3個變體,調用這些方法且將請求和響應對象傳入到容器的一個托管線程后將立即返回,在托管線程中異步操作將被執行。請求的分派器類型設置為異步(ASYNC)。不同于RequestDispatcher.forward(ServletRequest, ServletResponse) 分派,響應的緩沖區和頭信息將不會重置,即使響應已經被提交分派也是合法的??刂莆薪o分派目標的請求和響應,除非調用了ServletRequest.startAsync() 或 ServletRequest.startAsync(ServletRequest, ServletResponse),否則響應將在分派目標執行完成時被關閉。在調用了startAsync方法的容器啟動的分派沒有返回到容器之前任何dispatch方法的調用將沒有任何作用。AsyncListener.onComplete(AsyncEvent), AsyncListener.onTimeout(AsyncEvent)和AsyncListener.onError(AsyncEvent)的調用將被延遲到容器啟動的分派返回到容器之后。通過調用ServletRequest.startAsync.啟動的每個異步周期至多只有一個異步分派操作。相同的異步周期內任何試圖執行其他的異步分派操作是非法的并將導致拋出IllegalStateException。如果后來在已分派的請求上調用startAsync,那么所有的dispatch方法調用將和之上具有相同的限制。

?

■ 任何在執行dispatch方法期間可能拋出的錯誤或異常必須由容器抓住和處理,如下所示:

i. 調用所有由AsyncContext創建的并注冊到ServletRequest的AsyncListener 實例的AsyncListener.onError(AsyncEvent) 方法, 可以通過AsyncEvent.getThrowable()獲取到捕獲的Throwable。

ii. 如果沒有監聽器調用AsyncContext.complete 或任何AsyncContext.dispatch 方法,然后執行一個狀態碼為HttpServletResponse.SC_INTERNAL_SERVER_ERROR的出錯分派,并且可以通過RequestDispatcher.ERROR_EXCEPTION請求屬性獲取Throwable值。

iii. 如果沒有找到匹配的錯誤頁面,或錯誤頁面沒有調用AsyncContext.complete() 或任何AsyncContext.dispatch 方法,則容器必須調用AsyncContext.complete。

?

■ public boolean hasOriginalRequestAndResponse() – 該方法檢查AsyncContext 是否以原始的請求和響應對象調用ServletRequest.startAsync()完成初始化的,或者是否通過調用ServletRequest.startAsync(ServletRequest, ServletResponse)完成初始化的,且傳入的ServletRequest 和ServletResponse 參數都不是應用提供的包裝器,這樣的話將返回true。如果AsyncContext 使用包裝的請求及(或)響應對象調用ServletRequest.startAsync(ServletRequest, ServletResponse)完成初始化,那么將返回false。在請求處于異步模式后,該信息可以被出站方向調用的過濾器使用,用于決定是否在入站調用時添加的請求及(或)響應包裝器需要在異步操作期間被維持或者被釋放。

?

■ public void start(Runnable r) – 該方法導致容器分派一個線程,該線程可能來自托管的線程池,用于運行指定的Runnable對象。容器可能傳播相應的上下文信息到該Runnable 對象。

?

■ public void complete() – 如果調用了request.startAsync,則必須調用該方法以完成異步處理并提交和關閉響應。如果請求分派到一個不支持異步操作的Servlet,或者由AsyncContext.dispatch調用的目標servlet之后沒有調用startAsync,則complete方法會由容器調用。這種情況下,容器負責當servlet的service方法一退出就調用complete()。 如果startAsync 沒有被調用則必須拋出IllegalStateException。在調用ServletRequest.startAsync() 或ServletRequest.startAsync(ServletRequest, ServletResponse) 之后且在調用任意dispatch方法之前的任意時刻調用complete()是合法的。在調用了startAsync方法的容器啟動的分派沒有返回到容器之前該方法的調用將沒有任何作用。AsyncListener.onComplete(AsyncEvent)的調用將被延遲到容器啟動的分派返回到容器之后。

?

ServletRequestWrapper

■ public boolean isWrapperFor(ServletRequest req)- 檢查該包裝器是否遞歸的包裝了給定的ServletRequest,如果是則返回true,否則返回false。

?

■ ServletResponseWrapper

■ public boolean isWrapperFor(ServletResponse res)- 檢查該包裝器是否遞歸的包裝了給定的ServletResponse,如果是則返回true,否則返回false。

?

■ AsyncListener

■ public void onComplete(AsyncEvent event) – 用于通知監聽器在Servlet上啟動的異步操作完成了。

?

■ public void onError(AsyncEvent event) – 用于通知監聽器異步操作未能完成。

?

■ public void onStartAsync(AsyncEvent event) – 用于通知監聽器正在通過調用一個ServletRequest.startAsync方法啟動一個新的異步周期。正在被重新啟動的異步操作對應的AsyncContext可以通過調用給定的event上調用AsyncEvent.getAsyncContext獲取。

?

■ 在異步操作超時的情況下,容器必須按照如下步驟運行:

?

■ 當異步操作啟動后調用注冊到ServletRequest的所有AsyncListener實例的AsyncListener.onTimeout 方法。

?

■ 如果沒有監聽器調用AsyncContext.complete() 或任何AsyncContext.dispatch 方法,執行一個狀態碼為HttpServletResponse.SC_INTERNAL_SERVER_ERROR出錯分派。

?

■ 如果沒有找到匹配的錯誤頁面,或者錯誤頁面沒有調用AsyncContext.complete() 或任何AsyncContext.dispatch 方法,則容器必須調用AsyncContext.complete()。

?

■ 默認情況下是不支持JSP中的異步處理,因為它是用于內容生成且異步處理可能在內容生成之前已經完成。這取決于容器如何處理這種情況。一旦完成了所有的異步活動,使用AsyncContext.dispatch分派到的JSP頁面可以用來生成內容。

?

■ 下面所示的圖2-1描述了各種異步操作的狀態轉換。


Servlet3.1規范翻譯——Servlet接口
?

?

2.3.3.4 線程安全

除了startAsync 和complete 方法,請求和響應對象的實現都不保證線程安全。這意味著它們應該僅在請求處理線程范圍內使用或應用確保線程安全的訪問請求和響應對象。

如果應用使用容器管理對象創建一個線程,例如請求或響應對象,這些對象必須在其生命周期內被訪問,就像3.10和5.6章節定義的那樣。請注意,除了startAsync和complete方法,請求和響應對象不是線程安全的。如果這些對象需要多線程訪問,需要同步這些訪問或通過包裝器添加線程安全語義,比如,同步化調用訪問請求屬性的方法,或者在線程內為響應對象使用一個局部輸出流。

?

2.3.3.5 升級處理

在HTTP/1.1,Upgrade通用頭(general-header)允許客戶端指定其支持和希望使用的其他通信協議。如果服務器找到合適的切換協議,那么新的協議將在之后的通信中使用。Servlet容器提供了HTTP升級機制。不過,Servlet容器本身不知道任何升級協議。協議處理封裝在協議處理器。在容器和協議處理器之間通過字節流進行數據讀取或寫入。

當收到一個升級(upgrade)請求,servlet可以調用HttpServletRequest.upgrade方法啟動升級處理。應用準備和發送一個合適的響應到客戶端。退出servlet service方法之后,servlet容器完成所有過濾器的處理并標記連接已交給協議處理器處理。然后調用協議處理器的init方法,傳入一個WebConnection以允許協議處理器訪問數據流。

Servlet過濾器僅處理初始的HTTP請求和響應,然后它們將不會再參與到后續的通信中。換句話說,一旦請求被升級,它們將不會被調用。

協議處理器(ProtocolHandler)可以使用非阻塞IO(non blocking IO)消費和生產消息。

?

2.3.4 終止服務(End of Service)

Servlet容器沒必要保持裝載的Servlet持續任何特定的一段時間。一個Servlet實例可能會在servlet容器內保持活躍(active)持續一段時間(以毫秒為單位),Servlet容器的壽命可能是幾天,幾個月,或幾年,或者是任何之間的時間。

當Servlet容器確定servlet應該從服務中移除時,將調用Servlet接口的destroy方法以允許Servlet釋放它使用的任何資源和保存任何持久化的狀態。例如,當想要節省內存資源或它被關閉時,容器可以做這個。

在servlet容器調用destroy方法之前,它必須讓當前正在執行service方法的任何線程完成執行,或者超過了服務器定義的時間限制。

?

一旦調用了servlet實例的destroy方法,容器無法再路由其他請求到該servlet實例了。如果容器需要再次使用該servlet,它必須用該servlet類的一個新的實例。在destroy方法完成后,servlet容器必須釋放servlet實例以便被垃圾回收。

Servlet3.1規范翻譯——Servlet接口


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!??!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 97人人澡 | 久久精品中文字幕有码日本 | 精品自拍视频在线观看 | 日韩一级a毛片欧美一级 | 夜夜夜爽爽爽久久久 | 亚洲国产精品久久久久网站 | 欧美成人另类69 | 成人观看视频 | 四虎影视在线永久免费观看 | 99热久久国产精品这里有99 | 3d动漫免费一区二区三区 | 国内精品久久久久影院6 | 亚洲精品中文字幕久久久久久 | a级做爰视频在线观看 | 97精品久久天干天天蜜 | 春暖花开亚洲 | 看全色黄大色黄大片色责看的 | 女人夜色黄网在线观看 | 一本色道久久综合一区 | 亚洲天堂资源 | 国产欧美视频在线观看 | 99免费视频观看 | 四虎影视国产精品 | 小明看看成人免费 | 欧美三区在线 | 精品久久久久久国产91 | 五月色婷婷综合激情免费视频 | 中文字幕一区在线观看视频 | a一级毛片免费高清在线 | 国产在线91观看免费观看 | 天天翘夜夜洗澡天天做 | 99热99re8国产在线播放 | 精品国产成人系列 | 亚洲精品日韩一区二区 | 亚洲国产美女精品久久 | 毛片免费观看视频 | 色悠综合 | 欧美日韩一区在线观看 | 国产精品久久久久毛片 | 四虎网址 | 97香蕉久久夜色精品国产 |