9 Common Reasons Why @Async Doesn’t Work in Spring and How to Fix Them
This article explains nine typical scenarios that cause the Spring @Async annotation to fail—ranging from missing @EnableAsync to improper method visibility, return types, static or final modifiers, missing @Service, manual object creation, and incorrect component scanning—providing clear explanations and code examples for each case.
Introduction
A fan asked why a method annotated with @Async still executes synchronously, rendering the asynchronous behavior ineffective. Below is a pseudocode example:
@Slf4j
@Service
public class UserService {
@Async
public void async(String value) {
log.info("async:" + value);
}
}The article summarizes nine situations where @Async fails.
1. Missing @EnableAsync Annotation
To enable @Async, the project’s main class or a configuration class must be annotated with @EnableAsync. Without it, the asynchronous feature remains disabled.
@EnableAsync
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}2. Internal Method Calls
Calling an @Async method from another method within the same class uses the original object (equivalent to this.async()) instead of the Spring‑generated proxy, causing the async behavior to be lost.
@Slf4j
@Service
public class UserService {
public void test() {
async("test");
}
@Async
public void async(String value) {
log.info("async:{}", value);
}
}The method must be invoked on the proxy bean for @Async to work.
3. Method Not Public
Spring AOP can only proxy public methods. If an @Async method is declared with private, protected, or package‑private visibility, the asynchronous feature will not be applied.
4. Incorrect Return Type
@Async methods must return void or a Future type. Returning other types (e.g., String) prevents the async execution.
@Service
public class UserService {
@Async
public String async(String value) {
log.info("async:{}", value);
return value;
}
}5. Method Declared static
Static methods cannot be overridden, so Spring cannot create a proxy for them. Annotating a static method with @Async results in a compilation error: “Methods annotated with '@Async' must be overridable.”
@Slf4j
@Service
public class UserService {
@Async
public static void async(String value) {
log.info("async:{}", value);
}
}6. Method Declared final
Final methods are also non‑overridable, leading to the same proxy‑generation issue as static methods.
@Slf4j
@Service
public class UserService {
public void test() {
async("test");
}
@Async
public final void async(String value) {
log.info("async:{}", value);
}
}7. Service Class Missing @Service (or @Component/@Controller)
If a class containing an @Async method is not managed by Spring (i.e., lacks @Service, @Component, or @Controller), the async functionality will not be applied.
@Slf4j
// @Service // missing annotation
public class UserService {
@Async
public void async(String value) {
log.info("async:{}", value);
}
}
@Service
public class TestService {
@Autowired
private UserService userService;
public void test() {
userService.async("test");
}
}8. Manually Instantiating the Service
Creating a service instance with new bypasses Spring’s container, so the proxy (and thus @Async) is never applied.
@Slf4j
@Service
public class UserService {
@Async
public void async(String value) {
log.info("async:{}", value);
}
}
@Service
public class TestService {
public void test() {
UserService userService = new UserService();
userService.async("test");
}
}To use async behavior, obtain the bean from the Spring context or inject it.
9. Component Scan Does Not Include the Async Class
If @ComponentScan points to a non‑existent package or omits the package containing the @Async service, Spring will not detect the bean, and the async feature will be disabled.
@ComponentScan({"com.susan.demo.service1"})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}Ensure that the scan path includes all packages with async‑enabled services.
Conclusion
These nine scenarios cover the most common pitfalls that cause @Async to be ineffective. By checking each condition—enabling @EnableAsync, using public non‑static non‑final methods, returning appropriate types, annotating services, letting Spring manage beans, and configuring component scanning—you can ensure proper asynchronous execution in Spring applications.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
