SoFunction
Updated on 2025-03-08

Check out the pitfalls encountered by @Async annotation in SpringBoot and solutions

introduction

Spring Boot is a popular Java development framework that provides rich functions and convenient configurations, allowing developers to focus more on business logic. In terms of asynchronous programming, Spring Boot provides @Async annotation, which allows methods to be executed asynchronously and improves the concurrency performance of the system. However, there are some potential pitfalls to be paid attention to when using @Async annotation. This article will explore the 8 major pit points that may be encountered when using @Async annotation in Spring Boot and provide corresponding solutions.

1. Missing @EnableAsync annotation

In use@AsyncBefore annotation, you must add it on the main configuration class of the Spring Boot application@EnableAsyncAnnotation to enable support for asynchronous methods. If this step is ignored,@AsyncThe annotation will not take effect.

@SpringBootApplication
@EnableAsync
public class YourApplication {
    public static void main(String[] args) {
        (, args);
    }
}

2. Asynchronous methods need to be independent

quilt@AsyncAnnotation modified methods cannot be called directly by other methods in the same class. Because Spring will generate a proxy class at runtime, when calling an asynchronous method, it actually calls the method of this proxy class. Therefore, if the asynchronous method is called directly in the same class,@AsyncThe annotation will not take effect.

@Service
public class YourService {
    @Async
    public void asyncMethod() {
        // Logic of asynchronous execution    }

    public void callingAsyncMethod() {
        // Directly calling asyncMethod will not be executed asynchronously        asyncMethod();
    }
}

The solution is through injectionYourServicethe proxy object to call the asynchronous method.

@Service
public class YourService {
    @Autowired
    private YourService self;

    @Async
    public void asyncMethod() {
        // Logic of asynchronous execution    }

    public void callingAsyncMethod() {
        // Call asynchronous method through proxy object        ();
    }
}

3. Different asynchronous methods cannot be called each other

In the same class, if one asynchronous method calls another asynchronous method, there will also be a problem that it will not execute asynchronously. This is because Spring uses proxy-based AOP to implement asynchronous methods by default, and method calls inside the proxy object will not trigger AOP interception.

@Service
public class YourService {
    @Async
    public void asyncMethod1() {
        // Logic of asynchronous execution    }

    @Async
    public void asyncMethod2() {
        // Logic of asynchronous execution        asyncMethod1(); // The call here will not be executed asynchronously    }
}

The solution is to get the current proxy object through() and then call the asynchronous method.

@Service
public class YourService {
    @Autowired
    private YourService self;

    @Async
    public void asyncMethod1() {
        // Logic of asynchronous execution    }

    @Async
    public void asyncMethod2() {
        // Logic of asynchronous execution        self.asyncMethod1(); // Asynchronous execution through proxy object call    }
}

4. The asynchronous method with the return value void cannot catch the exception

If using@AsyncThe return value of the asynchronous method of the annotation isvoid, then the exception thrown in this method will not be caught. This is because exceptions cannot be passed between the calling thread of the asynchronous method and the thread that actually executes the asynchronous method.

@Service
public class YourService {
    @Async
    public void asyncMethod() {
        // Logic of asynchronous execution        throw new RuntimeException("Async method exception");
    }
}

The solution is to set the return value toFuture, so that you can call itget()Exception was caught during method.

@Service
public class YourService {
    @Async
    public Future<Void> asyncMethod() {
        // Logic of asynchronous execution        throw new RuntimeException("Async method exception");
    }
}

When calling an asynchronous method, you can useFutureofget()The method catches the exception.

@Service
public class YourService {
    @Autowired
    private YourService self;

    public void callAsyncMethod() {
        try {
            ().get();
        } catch (Exception e) {
            //Catch exception        }
    }
}

5. The method with @Async annotation cannot be called directly from the outside

If called directly in the same class with@AsyncThe annotation method cannot be executed asynchronously. Because Spring will generate a proxy class at runtime, external direct calls are actually called methods of the original class, not methods of the proxy class.

@Service
public class YourService {
    @Async
    public void asyncMethod() {
        // Logic of asynchronous execution    }
}

@Service
public class AnotherService {
    @Autowired
    private YourService yourService;

    public void callAsyncMethod() {
        // Directly calling asyncMethod from outside will not be executed asynchronously        ();
    }
}

The solution is through injectionYourServicethe proxy object to call the asynchronous method.

@Service
public class YourService {
    @Autowired
    private YourService self;

    @Async
    public void asyncMethod() {
        // Logic of asynchronous execution    }
}

@Service
public class AnotherService {
    @Autowired
    private YourService self;

    public void callAsyncMethod() {
        // Call asynchronous method through proxy object        ();
    }
}

6. @Async method does not work with private method

@AsyncAnnotations are only valid for public methods, so `private

The method cannot be executed asynchronously. If you try to give oneprivateMethod Add@Async` annotation will not produce any effect.

@Service
public class YourService {
    @Async
    private void asyncMethod() {
        // The @Async annotation here will not take effect    }
}

The solution is to extract the logic to be executed asynchronously into a public method and call this public method in the private method.

@Service
public class YourService {
    @Async
    public void asyncMethod() {
        doAsyncMethod();
    }

    private void doAsyncMethod() {
        // Logic of asynchronous execution    }
}

7. Missing asynchronous thread pool configuration

When using @Async annotation, Spring Boot creates a thread pool to execute asynchronous methods by default. If not configured, the default is SimpleAsyncTaskExecutor, which is a single-threaded executor that may cause performance bottlenecks.

To solve this problem, a suitable thread pool can be configured. Here is an example configuration:

@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        (5);
        (10);
        (25);
        ("Async-");
        ();
        return executor;
    }
}

This configuration is usedThreadPoolTaskExecutor, and set parameters such as the number of core threads, maximum number of threads, queue capacity, etc., and adjust them according to actual conditions.

8. Compatibility between asynchronous methods and transactions

By default, use@AsyncThe annotation method is incompatible with transactions. Because invoking the method using the transaction@AsyncWhen annotated methods, transactions will not be propagated into the asynchronous method, and the asynchronous method will be executed without transactions.

The solution is to@AsyncAnnotations are added to methods of another class, and asynchronous methods are called through proxy objects.

@Service
public class YourService {
    @Autowired
    private AsyncService asyncService;

    @Transactional
    public void transactionalMethod() {
        // Call asynchronous method in transaction        ();
    }
}

@Service
public class AsyncService {
    @Async
    public void asyncMethod() {
        // Logic of asynchronous execution    }
}

By moving the asynchronous method into another class, you can ensure that the asynchronous method is executed in a new transaction and does not conflict with external transactions.

Conclusion

use@AsyncAnnotations can improve the concurrency performance of the system, but some potential problems need to be paid attention to when using them. Learn more about Spring Boot@AsyncThese 8 major pit points annotated and corresponding solutions can better apply asynchronous programming to ensure the reliability and performance of the system. Hope this article helps you understand and use asynchronous annotations in Spring Boot.

The above is a detailed content of the pit points encountered and solutions encountered by @Async annotation in SpringBoot. For more information about SpringBoot @Async pit points, please follow my other related articles!