RESTEasy中的HTTP异步处理

转自:http://weli.iteye.com/blog/1273163

在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的网站中获取源代码: 
Bash代码   收藏代码
  1. svn export https://resteasy.svn.sourceforge.net/svnroot/resteasy/branches/Branch_2_1_0/ resteasy  


下载完成后,将RESTEasy源代码使用Maven进行编译安装: 

Bash代码   收藏代码
  1. mvn -Dmaven.skip.test=true install  

执行编译过程中,Maven会下载所依赖的库,需要不少的时间。完成后,我们便可以使用RESTEasy提供的异步调用HTTP请求的例子。这个例子位于刚刚签出的RESTEasy代码的examples/async-job-service中。 

这个例子中定义了一个非常简单的WebService: 

Java代码   收藏代码
  1. package org.jboss.resteasy.examples.asyncjob;  
  2.   
  3. import javax.ws.rs.Consumes;  
  4. import javax.ws.rs.GET;  
  5. import javax.ws.rs.POST;  
  6. import javax.ws.rs.PUT;  
  7. import javax.ws.rs.Path;  
  8. import javax.ws.rs.Produces;  
  9.   
  10. /** 
  11.  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> 
  12.  * @version $Revision: 1 $ 
  13.  */  
  14. @Path("/resource")  
  15. public class MyResource  
  16. {  
  17.    private static int count = 0;  
  18.   
  19.   
  20.    @POST  
  21.    @Produces("text/plain")  
  22.    @Consumes("text/plain")  
  23.    public String post(String content) throws Exception  
  24.    {  
  25.       Thread.sleep(1000);  
  26.       return content;  
  27.    }  
  28.   
  29.    @GET  
  30.    @Produces("text/plain")  
  31.    public String get() throws InterruptedException  
  32.    {  
  33.       return Integer.toString(count);  
  34.    }  
  35.   
  36.    @PUT  
  37.    @Consumes("text/plain")  
  38.    public void put(String content) throws Exception  
  39.    {  
  40.       System.out.println("IN PUT!!!!");  
  41.       Thread.sleep(1000);  
  42.       System.out.println("******* countdown complete ****");  
  43.       count++;  
  44.    }  
  45. }  

如代码所示,例子中定义了一个计数器的WebService,映射到URL地址/resource上,提供POST,GET,PUT方法。 

当使用POST方法访问/resources时,服务会把客户端提交的字串原封不动返回给用户;使用PUT方法访问时,将count计数器加1;使用GET方法调用则会获得计数器当前的值。 


值得注意的是put和post方法里面的两段代码: 

Java代码   收藏代码
  1. Thread.sleep(1000);  


让服务端在收到请求后休眠一秒钟后继续运行,目的是为了展示出异步执行的效果。针对这个WebService,例子中提供了一个测试类AsyncJobTest.java。 
可以看到这个类给出了两种模式的测试方法,分别是testOneway和testAsynch。 

testOneway  

testOneway调用/resources的put方法,并使用?oneway=true的参数,当RESTEasy收到oneway=true时,便知道要异步处理这个请求,并迅速返回给客户端一个 HTTP 202 ACCEPTED,然后再执行业务逻辑代码。上面看到,在put方法的服务端业务中,故意让这个线程休眠1秒钟,因此通过这个测试便可以展示出请求是异步执行的,客户端并不需要等这一秒钟,而是直接得到了 HTTP 202 ACCEPTED的返回。 

接下来的测试代码,让客户端得到服务器的返回后也休眠1.5秒钟,目的是等待服务器执行完put请求,将计数器加1,然后再通过get方法访问/resources,可以验证此时计数已经确实被加1了。 

testAsynch  

接下来是testAsynch方法。在这个测试方法中,首先向resource服务发起一个post请求,提交"content"字串。注意在这次提交中使用了?asynch=true的标记,向RESTEasy声明使用async模式。因此服务端收到请求后,除了马上返回一个 HTTP 202 ACCEPTED以外,还会将一个Location属性封装进HTTP Header中。接下来的测试代码读取Location中提供的URL,并马上访问这个地址。因为此时服务端的业务设计成休眠一秒,因此从这个地址中肯定还得不到业务返回结果,因此仍然会得到HTTP 202 ACCEPTED的响应。接下来客户端代码休眠了1.5秒,再次尝试访问Location给出的URL,此时应该得到了业务逻辑的正确返回,即"content"字串。 

执行上述测试,可在这个例子的根目录下使用下述maven命令: 

Bash代码   收藏代码
  1. mvn integration-test  


以上是对RESTEasy的轻量级HTTP异步请求模式的一个简单说明。在本文的下半部分,我将深入这个例子,动手做一些实验,加深对这两个模式的理解。 

参考书目: 
http://www.amazon.com/Restful-Web-Services-Leonard-Richardson/dp/0596529260/ref=sr_1_1?ie=UTF8&qid=1298825300&sr=8-1 
参考文档: 

http://docs.jboss.org/resteasy/docs/1.1.GA/userguide/html/async_job_service.html 



###################################################################

在RESTFul WebService一书中,介绍了使用HTTP协议来实现异步请求的一个轻量级设计模式,叫做ASync Job Service。而RESTEasy很好地支持了这个模式,并提供了一个例子说明使用方法。

我们仍然使用RESTEasy中提供的async-job-service这个例子来进行展示。这次我们来通过手工操作这个例子,而不是例子中提供的单元测试,来学习RESTEasy支持的两种轻量级HTTP异步处理方式。 

首先需要对MyResource.java做一些改造。将post和put方法中的两处: 

Java代码   收藏代码
  1. Thread.sleep(1000);  

改成: 
Java代码   收藏代码
  1. Thread.sleep(100000);  

通过将线程的等待时间由1秒改为100秒,我们可以有充分的时间来进行一些手工操作,查看程序运行效果。 

修改完成后,我们将WebService服务启动起来,在例子的根目录执行: 
Bash代码   收藏代码
  1. mvn jetty:run  

将服务启动。接下来使用linux下面的curl命令来访问webservice。我们分别使用oneway方式及async方式来访问。首先是oneway方式: 
Bash代码   收藏代码
  1. curl -X PUT -v http://localhost:9095/resource?oneway=true  

结果如下: 
Bash代码   收藏代码
  1. * About to connect() to localhost port 9095 (#0)  
  2. *   Trying ::1... connected  
  3. * Connected to localhost (::1) port 9095 (#0)  
  4. > PUT /resource?oneway=true HTTP/1.1  
  5. > User-Agent: curl/7.21.2 (x86_64-apple-darwin10.6.0) libcurl/7.21.2 OpenSSL/1.0.0c zlib/1.2.5 libidn/1.19  
  6. > Host: localhost:9095  
  7. > Accept: */*  
  8. >   
  9. < HTTP/1.1 202 Accepted  
  10. < Content-Length: 0  
  11. < Server: Jetty(6.1.15)  
  12. <   
  13. * Connection #0 to host localhost left intact  
  14. * Closing connection #0  

虽然服务中通过Thread.sleep()@ 指定了处理这个请求需要至少100秒,但是我们指定了使用 @oneway=true的异步方式来访问,因此服务器即时返回给客户端一个 HTTP 202 ACCEPTED,注意上面日志中的: 
Bash代码   收藏代码
  1. HTTP/1.1 202 Accepted  

使用oneway方式的问题在于:我们发出请求之后就,就无法得知服务器的处理结果了。因此RESTEasy提供了另一种async方式。我们来玩玩看,仍然是使用curl命令来访问服务: 
Bash代码   收藏代码
  1. curl -d "abc" -H "Content-Type:text/plain" -v http://localhost:9095/resource?asynch=true  

上面的curl命令通过POST方法访问/resource服务,提交contents参数为"abc"。查看服务端的代码,便知道/resources的POST方法接受客户端提交的content参数,睡眠100秒,然后返回给客户端content的值。 

此时服务的返回与oneway时类似,但多了一个Location的Header: 
Bash代码   收藏代码
  1. ...  
  2. < HTTP/1.1 202 Accepted  
  3. < Location: http://localhost:9095/asyncjobs/1299164229789-1  
  4. ...  

可以看到,除了HTTP 202 ACCEPTED,服务返回给我们一个Location的Header,里面包含一个URL地址。这个地址就是用来查看异步请求的结果的。 

如果我们在得到Location中给出的这个URL地址后,马上访问它: 
Bash代码   收藏代码
  1. curl -v http://localhost:9095/asyncjobs/1299164229789-1  

此时会得到这样的结果: 
Bash代码   收藏代码
  1. < HTTP/1.1 202 Accepted  

因为我们设定服务要睡眠100秒后开始处理业务逻辑并返回。因此我们马上访问这个用于取得结果的URL时,仍然是HTTP 202 ACCPTED。 

等候1分半钟以上,再次访问试试看: 
Bash代码   收藏代码
  1. curl http://localhost:9095/asyncjobs/1299164229789-1  

得到了预期的结果: 
Bash代码   收藏代码
  1. abc  

此时网站的HTTP返回值为: 
Bash代码   收藏代码
  1. < HTTP/1.1 200 OK  
  2. < Content-Type: text/plain  

通过上述一系列实验,阐述了RESTEasy提供的轻量级HTTP异步化解决方案的使用方法。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值