๐ด The Error You're Seeing
Confirm this matches your console output. If it does, you're in the right place.
org.springframework.scheduling.annotation.AsyncConfigurationException: No AsyncConfigurer found.
at org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor.setBeanFactory(AsyncAnnotationBeanPostProcessor.java:123)โก Quick Fix Works 80% of the time
Add @EnableAsync to your main Application class or a @Configuration class.
@SpringBootApplication
@EnableAsync
public class Application { ... }๐ง Why this Happens
Tap to expand the deep technical explanation
You used the @Async annotation, but Spring's asynchronous execution infrastructure is either not enabled (missing @EnableAsync) or misconfigured. Without an AsyncConfigurer, Spring doesn't know which thread pool to use to execute the background task.
The HITEC City Parking Spot Analogy:
Imagine a restaurant manager asking a waiter to clean tables, but the manager never hired a cleaning staff (Thread Pool). The waiter has to clean the tables themselves, blocking the main dining room.
๐ How to Reproduce Confirm this is your error
Annotate a method with @Async but forget to add @EnableAsync, then call it. Spring throws AsyncConfigurationException: No AsyncConfigurer found.
๐ ๏ธ Solutions (3 Ways to Fix)
Add @EnableAsync annotation
๐ Use this if your @Async methods are running synchronously or throwing config errors.
Spring Boot does not enable asynchronous processing by default. You must explicitly turn it on with @EnableAsync.
@SpringBootApplication
@EnableAsync // Add this
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}Implement AsyncConfigurer interface
๐ Use this if you want to define a custom thread pool or exception handler.
Create a configuration class that implements AsyncConfigurer to gain fine-grained control over how @Async tasks are executed.
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.initialize();
return executor;
}
}Avoid self-invocation
๐ Use this if @EnableAsync is present but the method still runs synchronously.
Spring's @Async uses a proxy. If you call an @Async method from another method in the SAME class, the proxy is bypassed, and it runs synchronously. Inject the bean into itself.
@Service
public class ReportService {
@Autowired
private ReportService self; // Inject self
public void generate() {
self.generateAsync(); // Calls through proxy
}
@Async
public void generateAsync() { ... }
}๐ Version Notes
Uses SimpleAsyncTaskExecutor by default if no custom pool is defined.
Requires explicit configuration for robust production use.
๐ก๏ธ How to Prevent This Next Time
Always create a custom ThreadPoolTaskExecutor bean when using @Async in production to prevent unbounded thread creation.