Async in Spring Boot

What is @Async?

@Async allows a method to run asynchronously in a separate thread, so the caller does not wait for it to finish.

Typical use cases:

  • Sending emails / notifications
  • Writing audit logs
  • Calling slow external services
  • Background processing (non-blocking)

1️⃣ Enable Async Support

We must enable async processing explicitly.

📌 Without @EnableAsync, @Async will not work.


@SpringBootApplication
@EnableAsync
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}


2️⃣ Configure Custom Thread Pool

Configuring a custom thread pool for @Async is not mandatory for functionality, but it is strongly recommended for production systems. Relying on the default executor can lead to uncontrolled thread creation and performance issues.


@Configuration
public class AsyncConfig {

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


3️⃣ Exception Handling in @Async

❌ This will NOT catch exceptions

try {
    asyncMethod();
} catch (Exception e) { }

✅ Correct way (Async Exception Handler)

@Configuration
public class AsyncExceptionConfig implements AsyncConfigurer {

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) ->
            System.err.println("Async error in " + method.getName());
    }
}


4️⃣ Create an Async Method

@Service
@Slf4j
public class AsyncUseCase {

    @Async
    public void sendEmail(String email) {
        System.out.println("Thread: " + Thread.currentThread().getName());
        // simulate delay
        try {
            Thread.sleep(50000);
            log.info("Testing Async feature");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("Email sent to " + email);
    }
}

Rules for @Async

  • ✔ Method must be public
  • ✔ Must be called from another Spring bean
  • ❌ Self-invocation will NOT work

5️⃣ Call the Async Method


@RestController
@RequestMapping("/api/async")
public class BranchController {

    @Autowired
    private AsyncUseCase asyncUseCase;

    @GetMapping
    public String sendMail() {
        asyncUseCase.sendEmail("mohan@gmai.com");
        return "OK";
    }

}

🧠 Result:

  • API returns immediately
  • but the async method runs in background thread

6️⃣ @Async vs Kafka / Message Queue

@Async Kafka
In-memory Durable
Same JVM Distributed
Simple Event-driven
Not fault-tolerant Fault-tolerant
  • 📌 Use @Async for lightweight background tasks
  • 📌 Use Kafka for inter-service, reliable communication

7️⃣ When NOT to Use @Async

  • ❌ Business-critical workflows
  • ❌ Guaranteed delivery use cases
  • ❌ Heavy CPU-bound tasks
  • ❌ Cross-service communication

Summary

  • @Async = simple background execution
  • Always configure a custom thread pool
  • No self-invocation
  • Handle exceptions properly
  • Use Kafka for reliable, distributed async

This site uses Just the Docs, a documentation theme for Jekyll.