The main goal of this project is to explore basic features of @Async
spring annotation and compare results with non-concurrent approach.
References: https://spring.io/guides/gs/async-method/
References: http://www.baeldung.com/spring-async
This project shows how to create asynchronous queries using Spring.
Our approach is to run expensive jobs in the background and wait
for the results using Java’s CompletableFuture
interface.
-
Enable asynchronous support:
@Configuration @EnableAsync class AsyncConfig { @Bean Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(4); executor.setMaxPoolSize(4); executor.setQueueCapacity(500); executor.setThreadNamePrefix("EmailSender-"); executor.initialize(); return executor; } }
Remark:
asyncExecutor()
is used to customize default behaviour and is not mandatory. -
Annotate method with
@Async
, and set return type toCompletableFuture<XXX>
whereXXX
is a wanted return type, for example:String customMethod() { ... }
should be transformed to:
CompletableFuture<String> customMethod() { ... }
-
Consume it with
Completable API
, for example:CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[]{})).join();
CompletableFuture.allOf(completableFuture1, completableFuture2).join();
-
Extract requested return (note that
get()
throws checked exception):XXX xxx = completableFuture.join()
email-service
- microservice responsible for sending emails to given usersEmailController
- REST controller; receiveslogin-message
map, then asksslow-user-service
foremails
and sends messages- in
EmailService
we have the same methods:@Async
method -asyncSend
- concurrently sends messages- non-concurrent method -
send
- in
AppRunner
we simulate interactions and compare times
slow-user-service
UserController
returnsUser
bean (login, name, email...) for given login- in
UserRepository
we sleep thread foruser.repository.delay.seconds
(configurable inapplication.properties
) and then return requested user
Coverage: 93%