Могу ли я вернуть ответ API, не дожидаясь других внешних вызовов API в Spring Boot?

Это правильный способ использования @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;
  }
...
}
@Service
public class AnotherService {
  @Async
  public void emailUserInTheBackground(int userId) {
    // This might take a while...
    ...
  }
}

Поскольку emailUserInTheBackground() имеет аннотацию @Async и возвращаемый тип void, блокирует ли он вообще строку return someResponseDTO?

Все, что я хотел, это вернуть ответ вызывающей стороне без ожидания, потому что emailUserInTheBackground() занимает слишком много времени и не привязан напрямую к объекту ответа.


person isoplayer    schedule 28.12.2020    source источник


Ответы (2)


Да, это правильный способ запуска задачи в фоновом режиме, вы можете имитировать поведение блокировки потока, введя задержку.

@SpringBootApplication
@EnableAsync
public class MyApplication {

    public static void main(String[] arg) {
       SpringApplication.run(MyApplication.class);
    }
}

затем вам нужно пометить метод emailUserInTheBackground аннотацией @Async.

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

Теперь добавьте еще один регистратор после вызова метода, вы увидите, что вызов getUsers(...) завершается первым в другом потоке, даже если поток emailService заблокирован на 10 секунд.

anotherService.emailUserInTheBackground(userId);
System.out.println("Print from service: "+ Thread.currentThread().getName());

вы также можете использовать CompletableFuture для запуска задачи в фоновом режиме.

 public someResponseDTO getUsers(int userId) {
   // Do some logic
   ...
   // Call external API with another service method from another service impl
   CompletableFuture.runAsync(() -> anotherService.emailUserInTheBackground(userId)) 
   return someResponseDTO;
  }
person Govinda Sakhare    schedule 28.12.2020
comment
Я бы сказал, что весенние события были бы подходящим вариантом. - person silentsudo; 28.12.2020
comment
@silentsudo Спасибо, приятель. Но я никогда не использовал события Spring. можете опубликовать отдельный ответ. всегда приятно знать, что есть лучший способ сделать что-то :) - person Govinda Sakhare; 28.12.2020

Соответствующее поведение @Async описано в документация Spring:

Вы можете указать аннотацию @Async для метода, чтобы вызов этого метода происходил асинхронно. Другими словами, вызывающий объект возвращается сразу после вызова, в то время как фактическое выполнение метода происходит в задаче, которая была отправлена ​​в Spring TaskExecutor.

В случае, который вы описываете, поскольку метод emailUserInTheBackground аннотирован @Async и включена возможность выполнения асинхронного метода Spring, метод emailUserInTheBackground немедленно вернется, а вызов будет обработан в отдельном потоке. Значение someResponseDTO будет возвращено из метода getUsers, в то время как метод emailUserInTheBackground продолжит обработку в фоновом режиме.

person M. Justin    schedule 28.12.2020