JAX-RS 2:将Guava ListenableFuture用于异步资源

时间:2014-06-24 09:08:43

标签: java web-services rest asynchronous jax-rs

在JAX-RS 2中编写异步端点通常如下所示:

@GET
public void asyncGet(@Suspended final AsyncResponse asyncResponse) {
    new Thread(new Runnable() {

        @Override
        public void run() {
            String result = veryExpensiveOperation();
            asyncResponse.resume(result);
        }

        private String veryExpensiveOperation() {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                // ignore
            }
            return "DONE";
        }
    }).start();
}

但是,这种方法不是很好,因为它不是声明性的。我在一些JAX-RS应用程序中看到可以使用Google Guava并编写如下代码:

ListeningExecutorService executor = ...;

@GET
public ListenableFuture<String> asyncGet() {
    return executor.submit(new Callable<String>() {
        @Override
        public String call() {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                // ignore
            }
            return "DONE";
        }
    });
}

但是,我不知道如何设置JAX-RS 2实现来接受这种端点,而且我还没有弄清楚其他实现是如何做到的。

我如何配置,例如泽西岛接受这种异步声明?

2 个答案:

答案 0 :(得分:1)

恢复FutureCallback中的asyncRresponse

@GET
@Produces(MediaType.TEXT_PLAIN)
public void asyncGet(@Suspended final AsyncResponse asyncResponse) {
    ListenableFuture<String> future = asyncGet();
    Futures.addCallback(future, new FutureCallback<String>() {

        @Override
        public void onSuccess(String result) {
            asyncResponse.resume(result);
        }

        @Override
        public void onFailure(Throwable exception) {
            asyncResponse.resume(exception);
        }
    });
}

确保在web.xml

中的servlet配置中启用了异步请求
<servlet>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    ...
    <async-supported>true</async-supported>
</servlet>

并且您使用servlet 3.0 API。

答案 1 :(得分:0)

我不知道如何做你想做的事情,但更清晰的解决方案是创建一个通用的回调类:

class GenericFutureCallback<T> implements ListenableFutureCallback<T> {

        private AsyncResponse asyncResponse;
        private Response.Status status;

        public GenericFutureCallback(AsyncResponse asyncResponse, Response.Status status) {
            this.asyncResponse = asyncResponse;
            this.status = status;
        }

        @Override
        public void onFailure(Throwable ex) {
            asyncResponse.resume(ex);
        }

        @Override
        public void onSuccess(T result) {
            Response response = Response.status(status).entity(result).build();
            asyncResponse.resume(response);
        }

    }

然后你的控制器看起来像这样:

@GET
@Produces(MediaType.TEXT_PLAIN)
public void asyncGet(@Suspended final AsyncResponse asyncResponse) {
    ListenableFuture<String> future = asyncGet();
    GenericFutureCallback<String> callback = new GenericFutureCallback<String>(asyncRes, Response.Status.OK);
    Futures.addCallback(future, callback);
}