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.
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.
@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
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
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
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
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.
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!