As consumers of websites demand fast page rendering times we as engineers need to continue to look for ways to make systems perform. Let us examine how to make asynchronous native java calls within a spring container.
Detailed Video Notes
Making async calls can be very powerful but before running off integrating async calls within your java application it is important to know that it may not fix your bottleneck. In async design you are only as good as your fastest data call for instance, if you have a total of 5 calls, 3 render in 5 seconds while 2 render in 500 milliseconds, the best you can achieve running asynchronous is 5 seconds. Additional performance tuning may need to be performed at the various levels in your application such as your data access layer, network or application layer.
Getting started
[0:30]
For our exercise we will make a GET rest request to a url that kicks off four different method calls with a delay of 500 milliseconds. This pattern could be applied to any service or data access object. If you are making requests against a database be sure you have configured your connection pools appropriately.
We follow the spring boot tutorial create a project through spring initializr web interface selecting web project dependencies. Downloading and importing into eclipse we will add guava dependency.
Application configuration
[0:58]
Lets add @EnableAsync
to our Application
, which is an annotation that turns on springs async method execution. This annotation has similar proxying behaviors like @Cacheable
. One thing to note, if you are calling multiple methods wrapped with @Async
within the same class you will need to refactor the method into a new class due to the proxying behaviors.
Since we want to customize the java.util.concurrent.Executor
we will implement AsyncConfigurer
when doing so we are required to provide the executor itself and let spring know how to handle exceptions. Overriding getAsyncExecutor
method we will return a ThreadPoolTaskExecutor
a class that will manage the thread pool. Next returning SimpleAsyncUncaughtExceptionHandler
in getAsyncUncaughtExceptionHandler
will log any errors occurs.
Starting up our application we will see async has been configured and we can start wrapping our methods with @Async
.
Websphere thread management
For our example ThreadPoolTaskExecutor
is being used to manage threads but if you running in a container you should consider allowing it to handle thread management. For instance, web sphere has work managers that can be configured by using WorkManagerTaskExecutor
. Below is the bean and dependency to include in your springframework application.
Note: When initially setting up async with websphere I included the following dependency by mistake which resulted in the following error:
Creating a service
[1:51]
After set up and application configuration is completed we will create MySampleService
class that will contain callAsync
method. It is flagged with spring’s @Async annotation that will trigger spring to run the execution on a separate thread if the application is set up to. It also has a return type of Future
which is requirement to run methods asynchronous.
Filling in the method we will use guava's Stopwatch
as a timer and Thread.sleep(500)
to delay the execution of the method by 500 milliseconds. Finally returning a AsyncResult
which is a wrapper object that implements ListenableFuture
which spring borrowed from guava.
Creating a controller
[2:25]
After creating the lower level class we call it by exposing a url. Let's break down the taskExecutor
controller method. Guava's Stopwatch
will be used to calculate the duration of the execution of the method. Next four asyncResult*
variables will be created by calling mySampleService.callAsync
passing in number that represents execution order. Once the method executes processing immediately starts on a background thread while the main thread continues execution. It isn't until asyncResult.get()
that the main thread will fetch the results or if it is still processing it will wait until it completes.
Two usage notes, if you are running multiple async method calls you should put the slowest call first as it is kicked off in the order of execution. Second, if ever have questions while debugging if your processes is running asynchronously you could remove the @EnableAsync
in the Application
class and rerun your application.
Let's fire up our server and hope that it executes in less than 2 seconds.
Output
As we continue to shift towards performance as a feature it is important to understand how async calls can be used to help. Spring makes it fairly easy to set up but you should be aware of other impacts to your system for instances it is possible that running tasks asynchronous may slow down your request based on behavior of thread pools and be aware container threading impacts as well as having enough database connections.
Thanks for joining in today's level up, have a great day!