One of the functionalities of app that I'm developing is that an email is sent every time user get's his invoice registered in our system. Sending an email from Java app easy especially if using Spring framework. I use JavaMailSenderImpl and SimpleMailMessage from Spring framework and it works okay.
But I need to send email in a new thread so that communication with SMTP server does not slow down the rest of apps processes. Problem is that when I call
MailSender.send()
method from a new thread, email message is not sent, as opposed when sending in a same thread. I tried with spring's @Async annotation, spring Executor and plain old java.lang.Thread but it doesn't work.
Can email be send asynchronously in java with spring? Had anyone a similar issue with this? I can post some code samples if needed.
Tnx
1) Add task namespace into spring context. The following xsd is for Spring 3.0 release.
xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd
2) Declare the executor in your spring context file.
3) Configure this to Spring task
These are all the configuration you need in the Spring context file.
The method you need to perform asynchronously annotate it with @Async annotaion.
Now, all the methods annotated with @async will be handled be spring task executor asynchronously.
You need to enable the feature in Spring:
One of the known issues of executing code in an asynchronous thread is that the exceptions thrown by that code are lost, unless you provide a specific handler to catch them. The effect you see (namely, the
@Async
method failing both to properly execute and to show a clue for that failure in the form of a log or stacktrace of some sort) is typically produced by such an exception, indeed thrown but swallowed by the asynchronous thread.One of the many possible reasons why your
@Async
method works when synchronous is that you are doing some database operation from the method. It works when synchronous, because you are probably calling it from a@Transactional
method of another@Service
, so for that thread aSession
orEntityManager
is found; but it does not work when asynchronous, because in this case you are on a new thread, and if the@Async
method is not@Transactional
itself there is noSession
orEntityManager
that could perform the operation.TL;DR Provide an exception handler to catch exceptions that would be swallowed by the asynchronous thread otherwise, or for the sake of debugging use a big
try
/catch
for the body of the@Async
method. You will probably see some exception popping up, then you will need to take the proper actions to avoid it.It should work.
You need to tell Spring that it should pay attention to your
@Async
Annotation by:And there are some limitations you need to pay respect to: