RESTEasy中的HTTP异步处理(上)
在RESTFul WebService一书中,介绍了使用HTTP协议来实现异步请求的一个轻量级设计模式,叫做ASync Job Service。而RESTEasy很好地支持了这个模式,并提供了一个例子说明使用方法。本文对这种设计模式及其在RESTEasy下的使用方法做出说明。
ASync Job Service
一般情况下,当客户端对服务端发起HTTP请求后,服务端将会为客户端打开一个HTTP连接,然后处理客户端发来的请求,处理完成后将结果封装成HTTP Response转回客户端,从而完成一次HTTP请求。
上述过程中,服务端在进行业务处理时,服务器与客户端之间的连接会保持联系,直到服务器将HTTP请求处理结束。如果服务端业务处理时间较长,那么客户端在等待的时候将一直占用这个HTTP连接。而服务器的资源是有限的,可以同时处理的HTTP请求也有一定的上限,当服务器压力较大,接受请求数很多时,很多等待返回结果的客户端连接就会造成性能瓶颈。
因此,在RESTFul WebService一书中针对这种情况提出了两种轻量级的解决方案:
第一种叫做 Ony Way 模式。当用户访问服务器的某个URL地址时,服务器接受到客户端请求,并马上返回HTTP Response给客户端,然后再开始执行业务处理逻辑。与普通情况下的正常返回值 HTTP 200 OK 不同,服务器会返回给客户端 HTTP 202 ACCEPTED,告知客户端请求已收到。
这种模式的好处是客户端基本上不会占用服务器的连接数,缺点也是显而易见的,客户端并不能监控请求到底成功没有,也不能判定业务逻辑是否正常执行。不管服务器接受到请求后,是否成功处理了业务逻辑,客户端只会收到一个 HTTP 202 ACCEPTED的返回值,并没有其它的信息包含在内。
针对上述问题,RESTFul WebService这本书中在此基础上还提出了另一种异步请求模式,叫做 ASync 模式:针对第一种模式中,客户端无法获得请求的执行结果的情况,要求服务器在收到请求后,返回给用户HTTP 202 ACCEPTED的同时,在HTTP HEADER中封装一个Location的属性给用户。在这个Location属性当中,提供给客户端一个用于查看业务执行结果的URL地址。
如果客户端想查看请求的执行结果,便可以访问服务器服务返回的Location地址处获得结果。如果此时服务器仍未处理完毕,则还会立刻返回给客户端HTTP 202 Accepted。如果服务端处理完成了,便会把实际的请求结果返回给用户。
RESTEasy实现
RESTEasy实现了RESTFul WebService中所描述的上面这两种设计模式,并提供了一个例子来展示其用法,我们来简单看一下。首先是从RESTEasy的网站中获取源代码:
svn export https://resteasy.svn.sourceforge.net/svnroot/resteasy/branches/Branch_2_1_0/ resteasy
mvn -Dmaven.skip.test=true install
package org.jboss.resteasy.examples.asyncjob;import javax.ws.rs.Consumes;import javax.ws.rs.GET;import javax.ws.rs.POST;import javax.ws.rs.PUT;import javax.ws.rs.Path;import javax.ws.rs.Produces;/** * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @version $Revision: 1 $ */@Path("/resource")public class MyResource{ private static int count = 0; @POST @Produces("text/plain") @Consumes("text/plain") public String post(String content) throws Exception { Thread.sleep(1000); return content; } @GET @Produces("text/plain") public String get() throws InterruptedException { return Integer.toString(count); } @PUT @Consumes("text/plain") public void put(String content) throws Exception { System.out.println("IN PUT!!!!"); Thread.sleep(1000); System.out.println("******* countdown complete ****"); count++; }}Thread.sleep(1000);
mvn integration-test