Field note / Spring Boot

Asynchronous Methods in Spring Boot Using @Async

Learn how to use Spring Boot's @Async annotation for non-blocking method execution.

2 min read

  • Spring Boot
  • Java
  • Async
  • Threading

In modern backend development, asynchronous processing plays a crucial role in improving performance and responsiveness. Spring Boot provides a powerful mechanism for executing tasks asynchronously using the @Async annotation. This blog post will explore how to use @Async, its configuration, best practices, and some real-world use cases.

What is @Async in Spring Boot?

The @Async annotation in Spring allows methods to run asynchronously in a separate thread, enabling non-blocking execution. This is particularly useful when handling long-running tasks, such as sending emails, making API calls, or processing large amounts of data without blocking the main thread.

Key Features of @Async

  1. Runs in a Separate Thread: Spring executes it in a separate thread, allowing the caller to continue.
  2. Requires @EnableAsync: You must annotate a configuration class with @EnableAsync.
  3. Supports Future, CompletableFuture, or void Return Types.

Setting Up Asynchronous Processing

1. Add @EnableAsync to Your Configuration

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

@Configuration
@EnableAsync
public class AsyncConfig {
}

2. Create an Asynchronous Service

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;

@Service
public class AsyncService {

    @Async
    public void asyncMethod() {
        System.out.println("Executing in thread: " + Thread.currentThread().getName());
    }

    @Async
    public CompletableFuture<String> asyncMethodWithReturn() {
        return CompletableFuture.completedFuture("Hello from async method");
    }
}

3. Calling the Async Methods

@Component
public class AsyncCaller {

    @Autowired
    private AsyncService asyncService;

    public void callAsyncMethod() {
        asyncService.asyncMethod();
        asyncService.asyncMethodWithReturn().thenAccept(System.out::println);
    }
}

Important Considerations

1. Spring Beans Are Required

Methods annotated with @Async must be part of a Spring-managed bean, or they will not execute asynchronously.

2. Self-Invocation Won’t Work

Calling an @Async method from within the same class will execute synchronously because Spring uses proxy-based AOP.

3. Thread Pool Configuration

By default, Spring uses SimpleAsyncTaskExecutor. For production, define a custom thread pool:

@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("AsyncThread-");
        executor.initialize();
        return executor;
    }
}

4. Exception Handling

Exceptions in @Async methods are not propagated to the caller. Handle them inside the method or use CompletableFuture.exceptionally():

asyncService.asyncMethodWithReturn()
    .exceptionally(ex -> "Recovered from: " + ex.getMessage())
    .thenAccept(System.out::println);

Real-World Use Cases

Sending Emails Asynchronously

@Async
public void sendEmail(String recipient, String message) {
    System.out.println("Sending email to " + recipient);
}

Fetching Data from Multiple Sources

@Async
public CompletableFuture<Data> fetchDataFromApi1() {
    return CompletableFuture.supplyAsync(() -> apiClient.getData("api1"));
}

@Async
public CompletableFuture<Data> fetchDataFromApi2() {
    return CompletableFuture.supplyAsync(() -> apiClient.getData("api2"));
}

Conclusion

Spring Boot’s @Async annotation provides an elegant way to run methods asynchronously, improving application performance and responsiveness. By configuring thread pools, handling exceptions properly, and using best practices, you can efficiently execute tasks in a non-blocking manner.

← All writing