我可以在 Spring Boot 中返回 API 响应而无需等待其他外部 API 调用吗?

iso*_*yer 0 java spring asynchronous spring-boot spring-async

@Async这是Spring Boot 中正确的使用方法吗?

@Service
class someServiceImpl {
...
  public someResponseDTO getUsers(int userId) {
   // Do some logic
   ...
   // Call external API with another service method from another service impl
   anotherService.emailUserInTheBackground(userId);
   return someResponseDTO;
  }
...
}
Run Code Online (Sandbox Code Playgroud)
@Service
public class AnotherService {
  @Async
  public void emailUserInTheBackground(int userId) {
    // This might take a while...
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

既然emailUserInTheBackground()@Async注释和返回类型,它会完全void阻塞该行吗?return someResponseDTO

我想要的只是将响应返回给调用者而无需等待,因为emailUserInTheBackground()完成时间太长并且不直接绑定到响应对象。

Gov*_*are 5

是的,这是在后台运行任务的正确方法,您可以通过引入延迟来模仿线程阻塞行为。

@SpringBootApplication
@EnableAsync
public class MyApplication {

    public static void main(String[] arg) {
       SpringApplication.run(MyApplication.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

那么你需要用@Async注释来标记emailUserInTheBackground方法。

@Service
class AnotherService {

    @Async
    public void emailUserInTheBackground(int userId) {
       try {
          TimeUnit.SECONDS.sleep(10);
          System.out.println("Print from async: "+ Thread.currentThread().getName());
       } catch (InterruptedException e) {
          e.printStackTrace();
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,在方法调用之后再添加一个记录器,getUsers(...)即使 emailService 线程被阻塞 10 秒,您也会看到调用首先在不同的线程中完成。

anotherService.emailUserInTheBackground(userId);
System.out.println("Print from service: "+ Thread.currentThread().getName());
Run Code Online (Sandbox Code Playgroud)

您还可以使用 CompletableFuture 在后台运行任务。

 public someResponseDTO getUsers(int userId) {
   // some other task
   ...
   // Call external API with another service method from another service impl
   CompletableFuture.runAsync(() -> anotherService.emailUserInTheBackground(userId)) 
   return someResponseDTO;
  }
Run Code Online (Sandbox Code Playgroud)