使用Jersey在运行时确定同步或异步响应

Jas*_*lio 5 java rest asynchronous jersey

是否可以在运行时决定是否应同步或异步处理对资源端点的Jersey REST请求?我们举一个简单的例子.

同步版本:

@Path("resource")
public class Resource {
    @GET
    @Produces({MediaType.TEXT_PLAIN})
    public Response get() {
        return Response.ok("Hello there!").build();
    }
}
Run Code Online (Sandbox Code Playgroud)

异步版本:

@Path("resource")
public class Resource {
    @GET
    @Produces({MediaType.TEXT_PLAIN})
    public void get(@Suspended final AsyncResponse r) {
        r.resume(Response.ok("Hello there!").build()); // usually called somewhere from another thread
    }
}
Run Code Online (Sandbox Code Playgroud)

根据某些参数,我想在运行时决定是应该同步还是异步处理GET请求.http://server/resource在两种情况下,资源endpoint()的URL 必须相同.这可能吗?

当然,正如您在上面的示例中所看到的,同步版本可以通过简单调用以异步方式伪造AsyncResponse.resume(...).但是,我会避免创建异步响应的开销.

cas*_*lin 6

退后一步

在JAX-RS异步服务器API是所有关于如何容器将要管理的要求。但是它仍然可以保留请求,不会影响客户体验。

引用Jersey文档中有关Asynchronous Server API的信息:

请注意,使用服务器端异步处理模型不会改善客户端感知的请求处理时间。但是,通过将初始请求处理线程释放回I / O容器,可以增加服务器的吞吐量,而请求可能仍在队列中等待处理,或者处理仍在另一个专用线程上运行。释放的I / O容器线程可用于接受和处理新的传入请求连接。

下述方法不会为您的客户带来任何好处。

使用自定义标题

您可以为同步和异步方法使用不同的URL,并创建预匹配过滤器,该将在请求匹配开始之前执行。

为此,请实现并对其进行ContainerRequestFilter注释,@PreMatching并根据您的条件(标题,参数等),更改请求的URI:

@Provider
@PreMatching
public class PreMatchingFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {

        if (requestContext.getHeaders().get("X-Use-Async") != null) {
            requestContext.setRequestUri(yourNewURI);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

看一下API。ContainerRequestContext

使用自定义媒体类型

我尚未测试以下解决方案,但它应该可以工作。您可以为同步方法和异步方法保留相同的URL,只是为每种方法接受不同的内容类型。

例如:

  • 同步方式: @Consumes("application/vnd.example.sync+text")
  • 异步方法: @Consumes("application/vnd.example.async+text")

并根据您的条件使用PreMatchingFilter来更改Content-Type标题,如下所示:

if (useSync) {
    requestContext.getHeaders().putSingle(
        HttpHeaders.CONTENT_TYPE, "application/vnd.example.sync+text");
} else {
    requestContext.getHeaders().putSingle(
        HttpHeaders.CONTENT_TYPE, "application/vnd.example.async+text");
}
Run Code Online (Sandbox Code Playgroud)

根据文档,ContainerRequestContext#getHeaders()返回带有请求标头的可变映射。