Sending Email with spring in a new thread issue
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 开发者_如何学Cwith 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
It should work.
You need to tell Spring that it should pay attention to your @Async
Annotation by:
<task:annotation-driven />
And there are some limitations you need to pay respect to:
- the annotated method must belong to a spring bean
- the invocation of the annotated method must be executed from a different Spring Bean (if you are using standard Spring AOP).
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.
<!-- Executor for the methods marked wiht @async annotations -->
<task:executor id="asyncExecutor" pool-size="25" />
3) Configure this to Spring task
<!-- Configuration for the Runtime -->
<task:annotation-driven executor="asyncExecutor" />
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.
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 a Session
or EntityManager
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 no Session
or EntityManager
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.
You need to enable the feature in Spring:
@EnableAsync
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
精彩评论