In this short article we're going to learn how
we can speed up Spring's JavaMailSenderImpl with some thread-forking
AOP. Though we're using JavaMail as an example, this tutorial should be useful to
people looking for a code-based introduction to Spring's support for AOP. Note
at the outset that I don't really go into AOP concepts and terminology, but I
do show some simple code that you should be able to follow if you already know
the basic concepts and just want to see what the code looks like.
There are lots of situations in which we want our application to send out an
automated e-mail. You might for instance want to send a confirmation e-mail in
response to new user registrations or mailing list subscriptions and unsubscriptions.
In Spring this probably means that you would use one of the various
JavaMailSenderImpl.send() methods. Listing 1 shows a sample
applicationContext.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.5.xsd>
<jee:jndi-lookup id="mailSession" jndi-name="mail/Session" resource-ref="true"/>
<bean id="mailSender"
class="org.springframework.mail.javamail.JavaMailSenderImpl"
p:session-ref="mailSession"/>
<bean id="mailingListService"
class="app.service.MailingListServiceImpl"
p:mailSender-ref="mailSender"/>
...
</beans>
And listing 2 shows how it looks from the Java side:
package app.service;
... imports ...
public class MailingListServiceImpl implements MailingListService {
private JavaMailSender mailSender;
public void setMailSender(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
private void sendConfirmSubscriptionEmail(Subscriber subscriber) {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
String text = ...
try {
helper.setSubject("Please confirm your subscription");
helper.setTo(subscriber.getEmail());
helper.setFrom(noReplyEmailAddress);
helper.setSentDate(subscriber.getDateCreated());
helper.setText(text, true);
} catch (MessagingException e) {
throw new RuntimeException(e);
}
mailSender.send(message);
}
...
}
(For more information on Spring/JavaMail integration, please see my article Send E-mail Using Spring and JavaMail.)
This works fine, but one thing your end users might notice is a fairly
significant delay while JavaMailSenderImpl.send() does whatever
it's doing to send your e-mail (presumably negotiating
with the SMTP server and sending the actual e-mail). While the delay probably isn't
large enough to provoke rioting in the streets, it's certainly noticeable, and in many use
cases it's unnecessary. E-mail is itself an asynchronous communications medium,
so unless there's an important reason to let the end user know about errors
that may occur while trying to send the e-mail (and there may be), one option
you might consider is making the send() call on a separate thread.
Now let's look at a few different ways to do that.