考虑进入Web服务器的请求,调用REST API。该请求正在为服务器创建一个耗时的工作。因此,Web服务器代码会将作业委派给其他服务器以提供可扩展的解决方案。此方案通常使用Publisher-Subscriber模式实现。
到目前为止一切都那么好,但是如果我想保持结果的请求呢?我可以反过来转动Publisher-Subscriber,所以现在我的REST API代码将等待一些发布者在结果准备好时得到通知。
这种情况的问题是订阅通知是以异步方式完成的(这本身就是完美的)。因此,在Spring中实现REST API等待RabbitMQ的通知将如下所示:
@RequestMapping(value = "/url", method = RequestMethod.GET)
public ResponseEntity url()
{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
String command = "Job Description";
channel.basicPublish("", "Heavy Worker", null, command.getBytes());
Consumer consumer = new DefaultConsumer(channel)
{
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException
{
String result = new String(body, "UTF-8");
//return the result as the HTTP response
}
};
channel.basicConsume("Heavy Job Result", true, consumer);
}
我试图在上面的代码片段中说明的问题是,在channel.basicConsume("Heavy Job Result", true, consumer);
之后,响应将返回给客户端,Java将不会等待"Heavy Job Result"
准备好。< / p>
是否有一种已知的做法如何以非轮询方式保留请求的挂起?
答案 0 :(得分:3)
解决方案取决于繁重工作完成所需的时间。如果它在比服务器超时配置的时间更短的时间内完成,那么您只需返回CompletableFuture
或ListentableFuture
就可以阻止您的Web IO:
@RequestMapping(value = "/url", method = RequestMethod.GET)
public CompletableFuture<ResponseEntity> url() {
return CompletableFuture.supplyAsync(() -> {
// do your computations here
});
}
Spring会为你处理剩下的事情。
如果花费的时间超过服务器超时,则可以使用WebSockets在作业完成时处理从服务器向客户端发送消息。 查看Spring WebSocket Support。流程将是: