繁体   English   中英

无法在 SpringBoot 中实现简单的异步方法调用

[英]Trouble implementing simple async method call in SpringBoot

我试图在我的 SpringBoot 应用程序中实现一个非常简单的异步方法调用,但是无论我做什么,我都无法让它工作。 我看过几十个教程,但它们对于我正在做的事情来说似乎都不必要地复杂。 如果您能提供任何帮助,我将不胜感激。

本质上,当我的 SpringBoot 应用程序的某个 REST 端点被命中时,它会启动一个缓慢的任务。 我不想让客户端等待慢速任务完成才能获得响应,而是异步调用任务方法,并立即向客户端返回响应。 为简单起见,我想立即返回的响应是通用的——我不关心返回慢速任务本身的结果。

我正在使用 Java 8 和 SpringBoot 2.1.7


最初,我只从 2 个课程开始:

1) Class 1:

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

2) Class 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) Class 1:

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

2) Class 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) Class 3:

public class AsyncClass {
  @Async
  public static void asyncSlowTask(){
    // Sleep for 10s
    Thread.sleep(10000);
  }
}

不幸的是,这没有任何区别——只有在我的缓慢任务完成后,请求仍然返回。

我还尝试了一些其他的小变化(包括在每个类上放置@EnableSync@Configuration ),但没有一个起作用。


所以,这是我的问题:
1) 我是否需要将异步方法移动到第 3 个 class,或者我原来的两类设置是否足够好?
2) 哪个 class 应该有@EnableSync注解?
老实说,我完全不知道它应该在哪里 go——我所知道的是它应该在“你的一个@Configuration 类”中的 go,这对我来说毫无意义。
3)还有什么我做错了吗?

再次感谢您提供的任何帮助!

来自Spring 文档

The default advice mode for processing @Async annotations is proxy which allows for interception of calls through the proxy only. Local calls within the same class cannot get intercepted that way The default advice mode for processing @Async annotations is proxy which allows for interception of calls through the proxy only. Local calls within the same class cannot get intercepted that way

依赖于 spring 代理的任何功能(异步、调度程序、事务等)仅适用于由 spring 容器管理的 object。

你的代码应该是这样的,

@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);
  }
}

哪个 class 应该有 @EnableSync 注解?

您可以在Application class 或任何@Configuration class 上添加注释,这应该没问题。

尝试创建异步配置

@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
    @Bean(name = "threadPoolTaskExecutor")
    public Executor threadPoolTaskExecutor() {
        return new ThreadPoolTaskExecutor();
    }

    @Override
    public Executor getAsyncExecutor() {
        return new ThreadPoolTaskExecutor();
    }

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

并用@Async("threadPoolTaskExecutor")写下你的方法

@Async("threadPoolTaskExecutor")
public void asyncSlowTask() {
    Thread.sleep(10000);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM