2013年12月21日 星期六

Asynchronous Processing

譯者:許裕永
原文取自 Oracle JavaEE_Tutorial

Web containers in application servers normally use a server thread per client request. Under heavy load conditions, containers need a large amount of threads to serve all the client requests. Scalability limitations include running out of memory or exhausting the pool of container threads. To create scalable web applications, you must ensure that no threads associated with a request are sitting idle, so the container can use them to process new requests.
一般而言,網路應用程式伺服器中的網路容器會為每一個使用者端的請求建立一個 server 執行緒。在負載量很大的時候, 容器就必須建立大量的執行緒物件來服務所有使用者端的請求。但這樣一來,包含記憶體不足或耗盡容器中的執行緒池的問題便會限制住程式,讓程式無法有效率的處理最大量的工作。要建立可以有效率的處理最大量工作的網路應用程式,你必須確保關連到同一個請求的執行緒群中沒有閒置的,讓容器可以使用它們去處理新的請求。

There are two common scenarios where a thread associated with a request can be
sitting idle:
這裏有兩種常見的情節會造成執行緒的閒置:
l          The thread needs to wait for a resource to become available or process data before building the response. For example, an application may need to query a database or access data from a remote web service before generating the response.執行緒在建立回應之前必須等待資源有效化或處理資料。例如,應用程式必須在產生回應之前先向資料庫提出請求或從遠端網路伺服器存取資料。
l          The thread needs to wait for an event before generating the response. For example, an application may have to wait for a JMS message, new information from another client, or new data available in a queue before generating the response.執行緒必須在產生回應前等待一個事件。例如,應用程式在產生回應之前必須等待一個 JMS 的訊息、新資訊來自於另一個使用者或新資料在一個佇列之中。

These scenarios represent blocking operations that limit the scalability of web applications. Asynchronous processing refers to assigning these blocking operations to a new thread and retuning the thread associated with the request immediately to the container.
這樣的情節呈現出「阻礙運算」限制了應用程式有效率的處理最大量的工作。「非同步化處理」是說把這些「阻礙運算」分派給新的執行緒,而且把這個請求所關連的執行緒立刻歸還給容器。
譯者注:
blocking operations 譯為「阻礙運算」,意指可能會需要長時間等待的運算。
asynchronous processing 譯為「非同步處理」,意指處理「阻礙運算」的作法。

Asynchronous Processing in Servlets

Java EE provides asynchronous processing support for servlets and filters. If a servlet or a filter reaches a potentially blocking operation when processing a request, it can assign the operation to an asynchronous execution context and return the thread associated with the request immediately to the container without generating a response. The blocking operation completes in the asynchronous execution context in a different thread, which can generate a response or dispatch the request to another servlet.
Java EE  servlets  filers 提供「非同步處理」(「異步處理」)的支援。如果servlet  filter 在處理請求時,碰到了可能的「阻礙運算」,它可以把這個運算指派給非同步執行環境,並在產生叵應之前,立刻歸還這個請求關連的執行緒給容器。這個「阻礙運算」會由新的執行緒在非同步執行的環境完成,這個新的執行緒也可以產生回應或轉送該請求給另一個 servlet 

To enable asynchronous processing on a servlet, set the parameter asyncSupported to true on the @WebServlet annotation as follows:
有效化 servlet 的「非同步處理」,只要在 @WebServlet annotation 中設定 asyncSupported 的屬性為 true 就可以了。如下:

@WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true)
public class AsyncServlet extends HttpServlet { ... }

The javax.servlet.AsyncContext class provides the functionality that you need to perform asynchronous processing inside service methods. To obtain an instance of AsyncContext, call the startAsync() method on the request object of your service method; for example:
Javax.servlet.AsyncContext 類別提供了你在 service methods 中撰寫「非同步處理」的程式碼時所必須的功能性方法。在 service method 中呼叫request 物件的 startAsync() 方法,就能取得 AsyncContext 的實體;如範例:
譯者注: service mothods 指的是 doet(req, res) doPost(req,res) 等可以取得 request 物件的方法 


public void doGet(HttpServletRequest req, HttpServletResponse resp) {
...
AsyncContext acontext = req.startAsync();
...
}

This call puts the request into asynchronous mode and ensures that the response is not committed after exiting the service method. You have to generate the response in the asynchronous context after the blocking operation completes or dispatch the request to another servlet.
這個呼叫會讓 request 進入非同步模式,而且確保 response 不會在離開 service method 後交割。你必須於「阻礙運算」完成後,產生非同步情況下的 response或轉送 request 給其他 servlet 

This table describes the basic functionality provided by the AsyncContext class.
這份表格描述了 AsyncContext 類別提供的基本功能

Method signature
Description
void start(Runnable run)
The container provides a different thread in which the blocking operation can be processed.
容器提供不同的執行緒,讓每一個「阻礙運算」可以被處理。

You provide code for the blocking operation as a class that implements the Runnable interface.
你把「阻礙運算」的程式碼撰寫在實作 Runnable的類別之中。

You can provide this class as an inner class when calling the start method or use another mechanism to pass the AsyncContext instance to your class.
你可以在呼叫 start 方法時,把該類別寫成內部類別。或使用其他方式把 AsyncContext 的實體傳送給你的類別。
ServletRequest getRequest()
Gets the request that was used to initialize this AsyncContext by calling ServletRequest.startAsync() or ServletRequest.startAsync(ServletRequest, ServletResponse).
取得呼叫ServletRequest.startAsync() or ServletRequest.startAsync(ServletRequest, ServletResponse) 來初始化這個 AsyncContext request

 In the example above the request is the same as in the service method.
在上面的範例中,這個方法取得的 request  sevice method 中的 request 是同一個物件。

You can use this method inside the asynchronous context to obtain parameters from the request.
你可以在非同步情況下使用這個方法來獲得request  parameters 
ServletResponse getResponse()
Gets the response that was used to initialize this AsyncContext by calling ServletRequest.startAsync() or ServletRequest.startAsync(ServletRequest, ServletResponse).
取得呼叫ServletRequest.startAsync() or ServletRequest.startAsync(ServletRequest, ServletResponse) 來初始化這個 AsyncContext response

In the example above the response is the same as the service method.
在上面的範例中,這個方法取得的responsesevice method 中的response是同一個物件。

You can use this method inside the asynchronous context to write to the response with the results of the blocking operation.
你可以在非同步情況下使用這個方法把「阻礙運算」的結果寫到 response 
void complete()
Completes the asynchronous operation and closes the response associated with this asynchronous context.
完成非同步運算而且關閉這個非同步情況下的response 

You call this method after writing to the response object inside the asynchronous context.
你會在撰寫這個非同步情況下的 response 之後呼叫這個方法。
void dispatch(String path)
Dispatches the request and response objects to the given path.You use this method to have another servlet write to the response after the blocking operation completes.
轉送 request  response 物件到指定的 path 。你使用這個方法讓另一個 servlet 撰寫「阻礙運算」完成後的 response 


The interface javax.servlet. AsyncListener will be notified in the event that an asynchronous operation initiated on a ServletRequest to which the listener had been added has completed, timed out, or resulted in an error.
一個經由安裝了 AsyncListener ServletRequest 所初始化的非同步運算,產生了 completed , timedout, resulted in an error 事件時,會通知 界面 javax.servlet.AsyncListener

Methods of AsyncListener
Modifier and Type
Method and Description
void onComplete(AsyncEvent event)
Notifies this AsyncListener that an asynchronous operation has been completed.
通知這個 AsyncListener 一個非同步運算已經完成。
void onError(AsyncEvent event)
Notifies this AsyncListener that an asynchronous operation has failed to complete.
通知這個 AsyncListener 一個非同步運算無法完成。
void onStartAsync(AsyncEvent event)
Notifies this AsyncListener that a new asynchronous cycle is being initiated via a call to one of the ServletRequest.startAsync() methods.
通知這個 AsyncListener 經由某一個ServletRequest.startAsync() 方法的呼叫,一個新的非同步週期將要被初始化。
void onTimeout(AsyncEvent event)
Notifies this AsyncListener that an asynchronous operation has timed out.
通知這個 AsyncListener 一個非同步運算已經超過時間。


Waiting for a Resource

This section demonstrates how to use the functionality provided by the AsyncContext class for the following use case:
1.          A servlet receives a parameter from a GET request.
2.          The servlet uses a resource, such as a database or a web service, to retrieve information based on the value of the parameter. The resource can be slow at times, so this may be a blocking operation.
3.          The servlet generates a response using the result from the resource.
這個部份示範如何使用 AsyncContext 類別提供的基本功能來處理下列狀況:
1.          servlet 接收到一個含有一個參數的請求。
2.          servlet 會用到一個資源。而這個資源是要透過請求的參數,來取得像是資料庫或網路服務的資訊。這個資源的取得有可能需要一些時間,所以這可以算是一個「阻礙運算」。
3.          servlet 從這個資源的結果來產生 response 

The following code shows a basic servlet that does not use asynchronous processing:
下列程式碼展示了一個沒有使用「非同步處理」的一般 servlet 

@WebServlet(urlPatterns={"/syncservlet"})
public class SyncServlet extends HttpServlet {
private MyRemoteResource resource;
@Override
public void init(ServletConfig config) {
resource = MyRemoteResource.create("config1=x,config2=y");
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
response.setContentType("text/html;charset=UTF-8");
String param = request.getParameter("param");
String result = resource.process(param);
/* ... print to the response ... */
}
}

The following code shows the same servlet using asynchronous processing:
下列程式碼展示了相同的 servlet 使用「非同步處理」:

@WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true)
public class AsyncServlet extends HttpServlet {
/* ... Same variables and init method as in SyncServlet ... */
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
response.setContentType("text/html;charset=UTF-8");
final AsyncContext acontext = request.startAsync();
acontext.start(new Runnable() {
public void run() {
String param = acontext.getRequest().getParameter("param");
String result = resource.process(param);
HttpServletResponse response = acontext.getResponse();
/* ... print to the response ... */
acontext.complete();
           }
});
}

AsyncServlet adds asyncSupported=true to the @WebServlet annotation. The rest of
the differences are inside the service method:
l          request.startAsync() causes the request to be processed asynchronously; the
response is not sent to the client at the end of the service method.
l          acontext.start(new Runnable() {...}) gets a new thread from the container. The code inside the run() method of the inner class executes in the new thread. The inner class has access to the asynchronous context to read parameters from the request and write to the response. Calling the complete() method of the instance of  AsyncContext commits the response and sends it to the client.
AsyncServlet   @WebServlet annotation新增了asyncSupported=true 。其餘的不同在 service method 之中。
l          request.startAsync() 會造成 request 被非同步處理;而且response 不會在 service method 結束時傳遞給使用者端。
l          acontext.start(new Runnable() {...}) 從容器取得一個新的執行緒。這個新的執行緒會執行內部類別的 run() 方法中的程式碼。在這個內部類別中,它存取了非同步情況下的 request 的參數並寫到 response 裏。呼叫AsyncContext 實體的 complete() 方法來交割 response 並把它傳送到使用者端。

The service method of AsyncServlet returns immediately, and the request is processed
in the asynchronous context.
AsyncServlet  service method 會立刻 return ,而這個請求會在非同步情況下處理。

沒有留言:

張貼留言