Spring @Async and transaction management
Join the DZone community and get the full member experience.
Join For FreeIntroduction
There are cases in which it is necessary to execute pieces of code asynchronous. An example is the sending of a (JMS) message from your system to another system. If it is not important for the database transaction whether or not the message has been sent successfully you can send the message asynchronous. The advantage is that the user does not have to wait in the front-end while the message is being send. Another example of possible asynchronous execution is the case where messages have a clear ordering. In order to try to prevent message A from being overtaken by message B you might want to schedule the sending of message B asynchronous with a delay.
Spring Framework
Spring supports the asynchronous execution of methods on your @Component
s by means of the @Async
annotation. When using this annotation on a method of your @Component
Spring will always execute this method asynchronous. The Spring framework will use AOP (Aspect Oriented Programming) on the Spring proxy of the @Component
to wrap calls to this method in a Runnable
and schedule this Runnable
on a task executor. This task executor has a thread pool and when a thread in the pool becomes available the Runnable
will be executed on this thread. The caller of the method annotated with @Async
does not wait untill the Runnable
has been executed but terminates after the Runnable
has been scheduled.
Return values
If the method to be executed asynchronously has a return value it should return a Future
in its signature. This Future
can be used by the caller to track the progress of the asynchronous task and to retrieve the result of the task once it has been completely executed. The @Async
method should return an ASyncResult
(which implements the Future
interface) containing the actual result.
Transaction management
If the @Async
annotation is being used extra care should be taken with respect to transactions. In normal circumstances (without @Async
) a transaction gets propagated through the call hierarchy from one Spring @Component
to the other.
However, when a @Transactional
Spring @Component
calls a method annotated with @Async
this does not happen. The call to the asynchronous method is being scheduled and executed at a later time by a task executor and is thus handled as a 'fresh' call, i.e. without a transactional context. If the @Async
method (or the @Component
in which it is declared) is not @Transactional
by itself Spring will not manage any needed transactions.
In case the method sends a message to an ESB (Enterprise Service Bus) using JMS (or another protocol) this can lead to problems, because you probably want to use the transaction manager declared in your Spring application context (typically a JTA transaction manager). In order to make Spring manage the transaction of the @Async
method either the @Component
or the method itself should declare the @Transactional
annotation, this way Spring will manage the transaction even if a method is being executed asynchronous.
Caveats
A final reminder: both @Transactional
and @Async
work with AOP an proxying. The methods to which these annotation are applied should be public, otherwise the annotations are not picked up by Spring. When JUnit testing methods annotated with @Async
in combination with transactions and automatic rollbacks extra care should be taken, this will be the topic of another blog post in the near future.
Opinions expressed by DZone contributors are their own.
Comments