-1

Is this the correct way to use @Async in 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...
    ...
  }
}

Since emailUserInTheBackground() has @Async annotation and void return type, does it block the line return someResponseDTO at all?

All I wanted is to return the response to the caller without waiting because emailUserInTheBackground() takes too long to complete and isn't directly tied to the response object.

4

2 回答 2

3

Yes that is the correct way to run a task in the background, you can mimick the thread blocking behavior by introducing a delay.

@SpringBootApplication
@EnableAsync
public class MyApplication {

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

then you need to mark the emailUserInTheBackground method with @Async annotation.

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

Now add one more logger after a method call, you'll see getUsers(...) call completing first in a different thread even though the emailService thread is blocked for 10 seconds.

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

you can also use CompletableFuture to run a task in the background.

 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;
  }
于 2020-12-28T04:12:49.867 回答
1

The relevant behavior of @Async is documented in the Spring documentation:

You can provide the @Async annotation on a method so that invocation of that method occurs asynchronously. In other words, the caller returns immediately upon invocation, while the actual execution of the method occurs in a task that has been submitted to a Spring TaskExecutor.

In the case you're describing, since the emailUserInTheBackground method is annotated with @Async and Spring's asynchronous method execution capability is enabled, the emailUserInTheBackground method will return immediately, and the call will be processed in a separate thread. The someResponseDTO value will be be returned from the getUsers method while the emailUserInTheBackground method continues to be processed in the background.

于 2020-12-28T05:00:50.513 回答