java - 在 Spring Boot 中实现简单的异步方法调用时遇到问题

标签 java spring-boot asynchronous

我试图在我的 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/

相关文章:

asp.net - 如何在asp.net web应用中显示第一个异步结果?

c# - 使用最小起订量的同步方法测试 EF 异步方法

java - 嵌套泛型和通配符

c# - 如何将 .NET Web 服务转换为基于 Spring WS 的 Web 服务?

java - hibernate + Spring + Tomcat

java - 使用 spring CrudRepository 自定义查询

Spring Boot应用程序实际上在端口0上运行,而不是随机运行

java - Web3j 读取单个事务的所有发出事件

java - 在 pageObject.PartnerNavigationDrawer.Profile 处获取 java.lang.NullPointerException(PartnerNavigationDrawer.java :30) when I call method

c# - 使用 TcpClient 类 C# 的异步套接字客户端