Annotating a method of a bean with @Async will make it execute in a separate thread i.e. the caller will not wait for the completion of the called method.
Enable Async Support
The @EnableAsync annotation switches on Spring’s ability to run @Async methods in a background thread pool. For Enabling asynchronous processing with Java configuration got by simply adding the @EnableAsync to a configuration class:
@Configuration @EnableAsync public class SpringAsyncConfig { ... }
Asynchronous processing can also be enabled using XML configuration – by using the task namespace:
<task:executor id="myexecutor" pool-size="5" /> <task:annotation-driven executor="myexecutor"/>
Limitations for @Async
- it must be applied to public methods only
- self invocation – calling the async method from within the same class – won’t work
The reasons are simple – the method needs to be public so that it can be proxied. And self-invocation doesn’t work because it bypasses the proxy and calls the underlying method directly.
The @Async Annotation
Annotation that marks a method as a candidate for asynchronous execution. Can also be used at the type level, in which case all of the type’s methods are considered as asynchronous.
1. Methods with void Return Type
Following is the simple way to configure a method with void return type to run asynchronously:
@Async public void asyncMethodWithVoidReturnType() { System.out.println("Execute method asynchronously. " + Thread.currentThread().getName()); }
2. Methods With Return Type
@Async can also be applied to a method with return type – by wrapping the actual return in a Future:
@Service public class GitHubLookupService { RestTemplate restTemplate = new RestTemplate(); @Async public Future<User> findUser(String user) throws InterruptedException { System.out.println("Looking up " + user); User results = restTemplate.getForObject("https://api.github.com/users/" + user, User.class); // Artificial delay of 1s for demonstration purposes Thread.sleep(1000L); return new AsyncResult<User>(results); } }
Spring also provides an AsyncResult class which implements Future. This can be used to track the result of the asynchronous method execution.
Now, let’s invoke the above method and retrieve the result of the asynchronous process using the Future object
public void testAsyncAnnotationForMethodsWithReturnType() throws InterruptedException, ExecutionException { System.out.println("Invoking an asynchronous method. " + Thread.currentThread().getName()); Future<User> future = GitHubLookupService.findUser(user); while (true) { if (future.isDone()) { System.out.println("Result from asynchronous process - " + future.get()); break; } System.out.println("Continue doing something else. "); Thread.sleep(1000); } }
The Executor
By default, Spring uses a SimpleAsyncTaskExecutor to actually run these methods asynchronously. The defaults can be overridden at two levels – at the application level or at the individual method level.
1. Override the Executor at the Method Level
@Configuration @EnableAsync public class SpringAsyncConfig { @Bean(name = "threadPoolTaskExecutor") public Executor threadPoolTaskExecutor() { return new ThreadPoolTaskExecutor(); } }
Then the executor name should be provided as an attribute in @Async:
@Async("threadPoolTaskExecutor") public void asyncMethodWithConfiguredExecutor() { System.out.println("Execute method with configured executor - " + Thread.currentThread().getName()); }
2. Override the Executor at the Application Level
@Configuration @EnableAsync public class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } }
The configuration class should implement the AsyncConfigurer interface – which will mean that it has the implement the getAsyncExecutor() method. It’s here that we will return the executor for the entire application – this now becomes the default executor to run methods annotated with @Async.
Exception Handling
We’ll create a custom async exception handler by implementing AsyncUncaughtExceptionHandler interface. The handleUncaughtException() method is invoked when there are any uncaught asynchronous exceptions:
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler { @Override public void handleUncaughtException(Throwable throwable, Method method, Object... obj) { System.out.println("Exception message - " + throwable.getMessage()); System.out.println("Method name - " + method.getName()); for (Object param : obj) { System.out.println("Parameter value - " + param); } } }
When a method return type is a Future, exception handling is easy – Future.get() method will throw the exception.
But, if the return type is void, exceptions will not be propagated to the calling thread. Hence we need to add extra configurations to handle exceptions.
we also need to override the getAsyncUncaughtExceptionHandler() method to return our custom asynchronous exception handler:
@Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new CustomAsyncExceptionHandler(); }
Summary:
Congratulations! You’ve learned an asynchronous service. And also we have seen how to enable async call in spring framework.
Happy Spring Learning.
- Spring Interview Questions and Answers
- Spring AOP Interview Questions and Answers
- Spring MVC Interview Questions
- Spring Security Interview Questions and Answers
- Spring REST Interview Questions and Answers
- Spring Boot Interview Questions and Answers
- Spring Boot Microservices Interview Questions and Answers
- Dependency Injection (DI) in Spring
- Spring IoC Container
- What is Bean Factory in Spring
- ApplicationContext in Spring
- Bean Autowiring in Spring
- Spring Bean Scopes
- Create Custom Bean Scope in Spring Example
- Using ApplicationContextAware in Spring
- Spring Bean Life Cycle and Callbacks
- BeanPostProcessor in Spring
- BeanFactoryPostProcessor in Spring
- Annotations in Spring and Based Configuration
- Spring JSR-250 Annotations
- JSR 330 Annotations in Spring
- Spring @Component, @Repository, @Service and @Controller Stereotype Annotations
- Method injection with Spring using Lookup method property
- Spring AOP-Introduction to Aspect Oriented Programming
- @Aspect Annotation in Spring
- Spring AOP AspectJ @Before Annotation Advice Example
- Spring AOP Before Advice Example using XML Config
- Spring AOP AspectJ @After Annotation Advice Example
- Spring AOP After Advice Example using XML Config
- Spring AOP AspectJ @AfterReturning Annotation Advice Example
- Spring AOP After-Returning Advice Example using XML Config
- Spring AOP AspectJ @AfterThrowing Annotation Advice Example
- Spring AOP After Throwing Advice Example using XML Config
- Spring AOP AspectJ @Around Annotation Advice Example
- Spring AOP Around Advice Example using XML Config
- Spring AOP Proxies in Spring
- Spring AOP Transaction Management in Hibernate
- Spring Transaction Management
- Spring Declarative Transaction Management Example
- Spring AOP-Ordering of Aspects with Example
- Spring Security Java Based Configuration with Example
- Spring Security XML Namespace Configuration Example
Great article dinesh congrats on this one. Please elaborate the transaction propagation also. I think that will also useful for others and topic for the next article 🤔
Thanks, Sunny. I noticed your suggestion.