我正在尝试使用SprintBoot实现异步控制器。我想向控制器发出REST请求,以便控制器在工作继续在服务器上的同时立即返回。
我正在关注这个Spring示例:http : //spring.io/blog/2012/05/07/spring-mvc-3-2-preview-introducing- servlet-3-async-support
我怀疑这是配置问题。有人可以告诉我我所缺少的吗?我是Spring的新手,所以请您提供尽可能多的详细信息,我们将不胜感激。
使用工作的控制器,我进行了以下更改:
// 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"; } }; }
我可以给新的控制器打电话,但是下面有两个问题:
2015-03-06 16:36:10.592错误13012 — [MvcAsync1] oswcrequest.async.WebAsyncManager:由于超时或网络错误,无法完成异步处理
更新: 通过在应用程序文件中创建以下bean,我能够解决超时问题:
@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; }
但是对控制器的调用仍然不是异步的。在通话过程中,浏览器仍然挂起。
我仍在寻求有关如何在后台进行工作时如何立即返回对控制器的REST调用的帮助。
更新二
谢谢戴夫。我试图在bean中实现一个异步方法。
这是我的应用程序类:
@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类:
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(); } }
我的控制器方法:
@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的结果。该方法已成功调用,但未在后台调用。知道我可能会缺少什么吗?
作为测试,如果更改控制器方法以等待结果,则永远不会输入wait块:
@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}"; }
更新三
我更换了
CsvFileDifferConfiguration context = new CsvFileDifferConfiguration(); LongProcess process = context.longProcessBean();
与
@Autowired private LongProcess process;
这样就解决了问题。
我认为您误解了MVC异步(和Servlet 3)功能。如果您的控制器方法需要很长时间才能完成,它将在与用于处理传入请求的线程不同的线程中调用,但是它仍必须在同一HTTP连接上将数据返回给客户端,因此它可能会超时这种观点。要立即返回但在后台执行处理,则不需要异步MVC,您只需要在后台线程中进行昂贵的处理(例如,通过@Async在另一个方法中调用方法@Bean)。
@Async
@Bean