如何实现异步REST请求使用Springboot控制器? [英] How to implement an asynchronous REST request to a controller using Springboot?

查看:3028
本文介绍了如何实现异步REST请求使用Springboot控制器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现使用SprintBoot异步控制器。我想使REST请求到控制器,使得控制器立即返回,而工作继续在服务器上。

I'm trying to implement an asynchronous controller using SprintBoot. I want to make REST request to a controller so that the controller returns immediately, while the work continues on the server.

我在今年春天例如:<一href=\"http://spring.io/blog/2012/05/07/spring-mvc-3-2-$p$pview-introducing-servlet-3-async-support\">http://spring.io/blog/2012/05/07/spring-mvc-3-2-$p$pview-introducing-servlet-3-async-support

我怀疑这是一个配置问题。有人可以告诉我,我缺少的是什么?我是新来的春天所以,如果您能提供尽可能多的细节,可能这将是AP preciated。

I suspect this is a configuration problem. Can someone please tell me what I'm missing? I'm new to Spring so if you could please provide as much details as possible it would be appreciated.

使用我做了以下修改正在运行的控制器:

Using a working controller I made the following changes:

// Before
@RequestMapping(method=RequestMethod.POST)
public String processUpload(final MultipartFile file) {
    // ...
    return "someView";
}

// After
@RequestMapping(method=RequestMethod.POST)
public Callable<String> processUpload(final MultipartFile file) {

  return new Callable<String>() {
    public Object call() throws Exception {
      // ...
      return "someView";
    }
  };
}

我能够调用新的控制器,但我有以下两个问题:

I am able to call the new controller but I have two issues below:


  1. 新的控制器没有异步调用。在通话过程中的浏览器挂起。呼叫的确,虽然执行code。

  2. 请求超时此错误:

  1. The new controller is not called asynchronously. The browser hangs during the call. The call does execute the code though.
  2. The request times out with this error:

2015年3月6日16:36:10.592错误13012 --- [MvcAsync1] o.s.w.c.request.async.WebAsyncManager:无法完成异步处理由于超时或网络错误

2015-03-06 16:36:10.592 ERROR 13012 --- [ MvcAsync1] o.s.w.c.request.async.WebAsyncManager : Could not complete async processing due to timeout or network error

更新:
我能在我的应用程序文件创建以下bean来解决超时:

Update: I was able to resolve the timeout by creating the following bean in my application file:

@Bean
public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {

            @Override
            public void customize(Connector connector) {

                connector.setPort(9000);
                connector.setAsyncTimeout(60000);
            }
        });
        return factory;
    }

但是该呼叫到控制器仍不异步的。该浏览器仍然挂起呼叫的持续时间。

But the call the to the controller is still not asynchronous. The browser still hangs for the duration of the call.

我还在寻求帮助就如何使一个REST的呼叫控制器立即返回,而这样做的工作的背景。

I'm still looking for help on how to make a the REST call to the controller return immediately while doing the work in the background.

更新II

感谢您戴夫。我试图实现一个bean异步方法。

Thank you Dave. I have attempted to implement an async method in a bean.

下面是我的应用程序类:

Here is my application class:

@SpringBootApplication
@EnableAsync
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {

            @Override
            public void customize(Connector connector) {

                connector.setPort(9000);
                connector.setAsyncTimeout(60000);
            }
        });
        return factory;
    }
 }

下面是我的bean类:

Here is my bean class:

public class LongProcess {

    @Async
    public Future<String> call() {
        try {
            System.out.println("Sleeping now...");
            Thread.sleep(10000);
            return new AsyncResult<String>("Hey");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }

}

我的配置类:

@Configuration
@EnableAsync
public class LongProcessConfiguration implements AsyncConfigurer {

    @Bean
    public LongProcess longProcessBean() {
        return new LongProcess();
    }

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setMaxPoolSize(10);
        taskExecutor.setThreadNamePrefix("LULExecutor-");
        taskExecutor.initialize();
        return taskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }

}

我的控制器方法:

My controller method:

@RequestMapping("/utilities/longProcess")
    public String longProcess() {

        System.out.println("Starting long process...");
        CsvFileDifferConfiguration context = new CsvFileDifferConfiguration();
        LongProcess process = context.longProcessBean();
        Future<String> result = process.call();
        System.out.println("Done!");
        return "{success: 1}";

    }

这可惜还是没有立即返回。请注意,我不关心从LongProcess的结果。该方法被成功地调用,但不能在背景中。任何想法,我可能会丢失?

This unfortunately still does not return immediately. Note that I don't care about the result from LongProcess. The method is called successfully, but not in the background. Any idea what I might be missing?

作为测试,如果我更改控制器的方法来等待结果,等待块从未进入:

As a test, if I change the controller method to wait for the result, the wait block is never entered:

@RequestMapping("/utilities/longProcess")
    public String longProcess() throws InterruptedException {

        System.out.println("Starting long process...");
        CsvFileDifferConfiguration context = new CsvFileDifferConfiguration();
        LongProcess process = context.longProcessBean();
        Future<String> result = process.call();
        while (!(result.isDone())) {
            Thread.sleep(1); //10-millisecond pause between each check
            System.out.println("Waiting for Long Process...");
        }
        System.out.println("Done!");
        return "{success: 1}";

    }

更新III

我换成

CsvFileDifferConfiguration context = new CsvFileDifferConfiguration();
            LongProcess process = context.longProcessBean();

@Autowired
private LongProcess process;

这解决了这个问题。

and this solved the issue.

推荐答案

我想你误会了MVC异步(和Servlet 3)功能。如果你的控制器方法需要很长的时间来完成,将在不同的线程比用于处理传入请求所述一个被调用,但它仍然有将数据返回给客户端相同的HTTP连接上,因此它可以从超时该点的图。在你不需要异步MVC后台立即返回,但做加工,你只需要做一个后台线程昂贵的处理(例如通过调用 @Async 方法另一个 @Bean )。

I think you misunderstand the MVC async (and Servlet 3) features. If your controller method takes a long time to complete it will be called in a different thread than the one used to handle the incoming request, but it still has to return data to the client on the same HTTP connection, so it can time out from that point of view. To return immediately but do the processing in the background you don't need async MVC, you just need to do the expensive processing in a background thread (e.g. by calling an @Async method in another @Bean).

这篇关于如何实现异步REST请求使用Springboot控制器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆