Java 如何在RESTAPI中拥有订阅服务器?

Java 如何在RESTAPI中拥有订阅服务器?,java,rest,publish-subscribe,Java,Rest,Publish Subscribe,考虑一个请求进入web服务器,调用RESTAPI。此请求具有服务器的作业,这非常耗时。因此,web服务器代码将把作业委托给其他服务器,以提供可扩展的解决方案。此场景通常使用发布者-订阅者模式实现 到目前为止还不错,但是如果我想让请求挂起等待结果呢?我可以用另一种方式打开发布者订阅服务器,因此现在我的RESTAPI代码将等待结果就绪时通知某个发布者 这个场景的问题是,订阅通知是以异步方式完成的(这本身就是完美的)。因此,在Spring中实现REST API,等待RabbitMQ的通知,如下所示:

考虑一个请求进入web服务器,调用RESTAPI。此请求具有服务器的作业,这非常耗时。因此,web服务器代码将把作业委托给其他服务器,以提供可扩展的解决方案。此场景通常使用发布者-订阅者模式实现

到目前为止还不错,但是如果我想让请求挂起等待结果呢?我可以用另一种方式打开发布者订阅服务器,因此现在我的RESTAPI代码将等待结果就绪时通知某个发布者

这个场景的问题是,订阅通知是以异步方式完成的(这本身就是完美的)。因此,在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(“繁重的工作结果”,true,consumer)之后响应将返回给客户端,Java不会等待
准备“繁重的工作结果”


是否有一种已知的做法可以使消息的请求以非轮询方式挂起?

解决方案取决于完成繁重的工作所需的时间。如果它在少于服务器超时配置的时间内完成,那么您所要做的就是不通过返回
CompletableFuture
ListentableFuture
来阻止web IO,如下所示:

@RequestMapping(value = "/url", method = RequestMethod.GET)
public CompletableFuture<ResponseEntity> url() {
  return CompletableFuture.supplyAsync(() -> {
    // do your computations here
  });
}
@RequestMapping(value=“/url”,method=RequestMethod.GET)
公共CompletableFuture url(){
返回CompletableFuture.SupplySync(()->{
//你在这里计算吗
});
}
Spring将为您处理其余的事务

如果所需时间超过服务器超时时间,则可以使用WebSockets在作业完成时处理从服务器向客户端发送消息。 退房流程将是:

  • 接收请求
  • 将其交给新线程中的长时间运行的处理器(例如CompletableFuture.runAsync())
  • 启动此新线程后立即返回响应
  • 一旦作业完成,您将向前端发送一条消息,表明该作业已完成,并且包含了您想要包含的任何数据

  • @Mehran-如果你觉得答案有用,请接受。