开发者

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);
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜