我们应该始终将异步 JAX-RS 资源用于移动后端吗?
Should we always use Asynchronous JAX-RS resources For mobile backend?
我正在使用 Java EE - JAX-RS 2.0 技术构建移动后端 API。
由于移动客户端消费的大部分是异步 http 调用
所以我的问题是: 我是否应该对所有 JAX-RS 资源使用异步功能?如果不是,原因是什么?
下面是移动异步模板API
@Path("/async_api")
public class AsyncResource {
@GET
@Path("/loadUsers")
@Produces(MediaType.APPLICATION_JSON)
public void loadUsers(@Suspended AsyncResponse asyncResponse) {
//TODO: ManagedExecutorService
new Thread(new Runnable() {
@Override
public void run() {
List users = loadBigUsers();
asyncResponse.resume(users);
}
private List loadBigUsers() {
return null; // Return big list
}
}).start();
}
}
谢谢!
在 JAX-RS 中,@Suspend
注释和 AsyncResponse
仅在某些典型场景中才需要。第一种情况已在您的代码示例中确定。这是一个很长的 运行 任务。在这种情况下,AsyncResponse
可用于在后台线程中执行长 运行 代码。虽然乍一看这没有意义,但我们需要考虑应用程序服务器/容器如何处理其请求。通常有一个接受和处理客户端请求的线程池。如果您在 JAX-RS 服务方法中内联实现昂贵的操作,则池中的线程之一会在整个运行时被阻塞。使用 AsyncResponse
执行程序线程返回到池中,其他请求可以并行处理。
@Path("/users")
public class UserRestService {
@GET
public void getAllUsers(@Suspend final AsyncResponse asyncResponse) {
new Thread(new Runnable(
@Override
public void run() {
List<Users> users = UserDAO.loadAllUsers();
asyncResponse.resume(users);
}
) {}).start();
}
}
AsyncResponse
的第二个应用场景就是常见的生产者消费者模式。假设您有一个绑定到 URL https://yourservice.at/queue/next
的队列,那么 @GET
方法可用于阻塞 take()
假设 LinkedBlockingQueue
。在同一个 URL 上,您可以绑定一个 @POST
方法,该方法将数据添加到队列中。在这种情况下,您将在 AsyncResponse
.
中使用 take()
操作来完成功能
@Path("/queue/next")
public class MessageQueueService {
private static final LinkedBlockingQueue<AsyncResponse> suspendedResponses = new LinkedBlockingQueue<AsyncResponse>();
@GET
public void getNextMessage(@Suspend final AsyncResponse asyncResponse) {
MessageQueueService.suspendedResponses.put(asyncResponse);
}
@POST
public void putNewMessage(final String message) throws InterruptedException {
AsyncResponse asyncResponse = suspendedResponses.take(); // note how this could also block a thread
asyncResponse.resume(message);
}
}
从这些解释中您还可以看出,JAX-RS @Suspended
机制用于创建异步服务器端任务。同样的请求是否也在客户端以异步方式执行是完全不同的故事。
我正在使用 Java EE - JAX-RS 2.0 技术构建移动后端 API。
由于移动客户端消费的大部分是异步 http 调用
所以我的问题是: 我是否应该对所有 JAX-RS 资源使用异步功能?如果不是,原因是什么?
下面是移动异步模板API
@Path("/async_api")
public class AsyncResource {
@GET
@Path("/loadUsers")
@Produces(MediaType.APPLICATION_JSON)
public void loadUsers(@Suspended AsyncResponse asyncResponse) {
//TODO: ManagedExecutorService
new Thread(new Runnable() {
@Override
public void run() {
List users = loadBigUsers();
asyncResponse.resume(users);
}
private List loadBigUsers() {
return null; // Return big list
}
}).start();
}
}
谢谢!
在 JAX-RS 中,@Suspend
注释和 AsyncResponse
仅在某些典型场景中才需要。第一种情况已在您的代码示例中确定。这是一个很长的 运行 任务。在这种情况下,AsyncResponse
可用于在后台线程中执行长 运行 代码。虽然乍一看这没有意义,但我们需要考虑应用程序服务器/容器如何处理其请求。通常有一个接受和处理客户端请求的线程池。如果您在 JAX-RS 服务方法中内联实现昂贵的操作,则池中的线程之一会在整个运行时被阻塞。使用 AsyncResponse
执行程序线程返回到池中,其他请求可以并行处理。
@Path("/users")
public class UserRestService {
@GET
public void getAllUsers(@Suspend final AsyncResponse asyncResponse) {
new Thread(new Runnable(
@Override
public void run() {
List<Users> users = UserDAO.loadAllUsers();
asyncResponse.resume(users);
}
) {}).start();
}
}
AsyncResponse
的第二个应用场景就是常见的生产者消费者模式。假设您有一个绑定到 URL https://yourservice.at/queue/next
的队列,那么 @GET
方法可用于阻塞 take()
假设 LinkedBlockingQueue
。在同一个 URL 上,您可以绑定一个 @POST
方法,该方法将数据添加到队列中。在这种情况下,您将在 AsyncResponse
.
take()
操作来完成功能
@Path("/queue/next")
public class MessageQueueService {
private static final LinkedBlockingQueue<AsyncResponse> suspendedResponses = new LinkedBlockingQueue<AsyncResponse>();
@GET
public void getNextMessage(@Suspend final AsyncResponse asyncResponse) {
MessageQueueService.suspendedResponses.put(asyncResponse);
}
@POST
public void putNewMessage(final String message) throws InterruptedException {
AsyncResponse asyncResponse = suspendedResponses.take(); // note how this could also block a thread
asyncResponse.resume(message);
}
}
从这些解释中您还可以看出,JAX-RS @Suspended
机制用于创建异步服务器端任务。同样的请求是否也在客户端以异步方式执行是完全不同的故事。