我试图在我的 SpringBoot 应用程序中实现一个非常简单的异步方法调用,但是,无论我做什么,我就是无法让它工作。我已经看过几十个教程,但对于我正在做的事情来说,它们似乎都不必要地复杂。如果您能提供任何帮助,我将不胜感激。
本质上,当我的 SpringBoot 应用程序的某个 REST 端点被命中时,它会启动一个缓慢的任务。我不想让客户端等待缓慢的任务完成后再获得响应,而是想异步调用任务方法,并立即向客户端返回响应。为简单起见,我想立即返回的响应是通用的——我不关心返回慢速任务本身的结果。
我正在使用 Java 8 和 SpringBoot 2.1.7
最初,我只学习了 2 门类(class):
1) 第 1 类:
@SpringBootApplication
@EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
2) 第 2 类:
@RestController
@RequestMapping("/rest")
public class Controller {
@RequestMapping(value = "/slowTask", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<?> slowTask() {
try{
asyncSlowTask();
// Want below response to be immediate -- instead, only occurs after above function is done.
return new ResponseEntity<String>("Accepted request to do slow task", HttpStatus.ACCEPTED);
}
catch (Exception e) {
return new ResponseEntity<String>("Exception", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@Async
public void asyncSlowTask(){
// Sleep for 10s
Thread.sleep(10000);
}
}
我通过本地点击应用程序进行了测试:curl http://localhost:8080/rest/slowTask
我期望的是 curl
命令会立即返回 - 相反,它仅在 10 秒后返回(在我的缓慢任务完成之后)。
此时,我读到异步方法不应该“自调用”——我不知道这是否是我正在做的事情,但是为了安全起见,我将异步方法移到了一个新类中,这样我的类(class)现在看起来像这样:
1) 第 1 类:
@SpringBootApplication
@EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
2) 第 2 类:
@RestController
@RequestMapping("/rest")
public class Controller {
@RequestMapping(value = "/slowTask", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<?> slowTask() {
try{
AsyncClass.asyncSlowTask();
// Want below response to be immediate -- instead, only occurs after above function is done.
return new ResponseEntity<String>("Accepted request to do slow task", HttpStatus.ACCEPTED);
}
catch (Exception e) {
return new ResponseEntity<String>("Exception", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
3) 第 3 类:
public class AsyncClass {
@Async
public static void asyncSlowTask(){
// Sleep for 10s
Thread.sleep(10000);
}
}
不幸的是,这没有任何区别——只有在我的缓慢任务完成后,请求仍然返回。
我还尝试了许多其他细微的变化(包括在每个类上放置 @EnableSync
和 @Configuration
),但没有一个起作用。
所以,这是我的问题:
1)我是否需要将异步方法移至第三类,或者我原来的两类设置是否足够好?
2) 哪个类应该有@EnableSync
注解?
老实说,我完全不知道它应该去哪里——我所知道的是它应该放在“你的一个@Configuration类”中,这对我来说没有任何意义。
3)我还有什么做错的吗?
再次感谢您提供的任何帮助!
最佳答案
来自Spring Doc ,
处理 @Async 注解的默认建议模式是代理,仅允许通过代理拦截调用。同一类中的本地调用无法以这种方式被拦截
。
任何依赖于 Spring 代理的功能(异步、调度程序、事务等)仅适用于 Spring 容器管理的对象。
你的代码应该是这样的,
@RestController
@RequestMapping("/rest")
public class Controller {
private final AsyncClass asyncClass;
public Controller(final AsyncClass asyncClass) {
this.asyncClass = asyncClass;
}
@RequestMapping(value = "/slowTask", method = RequestMethod.GET)
public ResponseEntity<?> slowTask() {
try {
asyncClass.asyncSlowTask();
return new ResponseEntity<>("Accepted request to do slow task", HttpStatus.ACCEPTED);
} catch (final RuntimeException e) {
return new ResponseEntity<>("Exception", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
@Component
public class AsyncClass {
@Async
@SneakyThrows
public void asyncSlowTask() {
Thread.sleep(10000);
}
}
Which class should have the @EnableSync annotation?
您可以在 Application
类或任何 @Configuration
类上添加注释,这应该没问题。
关于java - 在 Spring Boot 中实现简单的异步方法调用时遇到问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61741944/