del.icio.us Digg DZone Reddit StumbleUpon
AOP 101: Speeding Up Spring's JavaMailSenderImpl with AOP - Willie Wheeler
« Previous | 1 | 2 | 3

Method 3: Use AOP to wrap JavaMailSenderImpl.send()

This is a fun and elegant method. Even though this article is called "AOP 101", I'm not planning to explain the concepts or weird terminology; rather I just want to show you the code and assume that you'll be able to see what's happening.

First we need to create an "advice" class. This is the code that we're going to wrap around our send() invocations. Listing 3 shows the code.

Listing 3. ForkAdvice.java, which will wrap our send() invocations
package app.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;

public class ForkAdvice {
    private static final Logger log = Logger.getLogger(ForkAdvice.class);
    
    public void fork(final ProceedingJoinPoint pjp) {
        new Thread(new Runnable() {
            public void run() {
                log.info("Forking method execution: " + pjp);
                try {
                    pjp.proceed();
                } catch (Throwable t) {
                    // All we can do is log the error.
                    log.error(t);
                }
            }
        }).start();
    }
}

The fork method is "around" advice that we're going to use to advise our calls to JavaMailSenderImpl.send(). As you can see, it creates a new thread and starts it. In the run() body, we simply execute the advised method by calling pjp.proceed().

As an aside, the ProceedingJoinPoint class is provided by the AspectJ class library, but note that we're not using full-blown AspectJ here—we're in fact using Spring AOP. Full AspectJ involves a special aspect language and compiler to generate classes with the advice woven into the class bytecode itself. Spring AOP on the other hand uses dynamic proxies (either the interface variety that comes with Java, or else class proxies via CGLIB) to advise classes. While Spring AOP borrows classes and also the AspectJ pointcut language from AspectJ, its use of dynamic (runtime) proxies as opposed to bytecode-level advice integration distinguishes it from AspectJ.

Now it's time to update our application context with our AOP configuration. We do this in listing 4 below.

Listing 4. Our updated applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop"
    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/aop
        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
        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"/>
        
    <bean id="forkAdvice" class="app.aop.ForkAdvice"/>
    
    <aop:config>
        <aop:aspect ref="forkAdvice">
            <aop:around method="fork"
pointcut="execution(* org.springframework.mail.javamail.JavaMailSenderImpl.send(..))"/>
        </aop:aspect>
    </aop:config>
    
    ...
    
</beans>

This is similar to what we had before, but there are a couple of differences. First, note that we've declared the aop namespace here. That of course allows us to use the namespace configuration feature that Spring 2.0 introduced. The other change is that we've added a definition for our advice bean as well as some AOP configuration. In aop:aspect we point to our forkAdvice as the advising class to be applied, we indicate that it will be "around" advice, we specify the advising method, and finally we specify a pointcut that indicates which method calls will be advised/wrapped. We use the AspectJ pointcut language to specify a pointcut. Here we're indicating that we want all calls to any of the JavaMailSenderImpl.send() methods to be advised.

As mentioned previously, this technique is like the wrapper technique in that you can use it to add the forking behavior in a way that's transparent to client code. Moreover you can use it not just for JavaMail but really for any method where you want to create a new thread before executing the method. You just add the appropriate aop:around definitions to the aop:aspect definition and you're in business.

Have fun!

Social bookmarks: del.icio.us Digg DZone Reddit StumbleUpon
« Previous | 1 | 2 | 3

Comments (11)

Hi Willie.

Nice article: a good illustration of AOP in action.

Unfortunately, the expected Listing 3 does not contain the expected AspectJForkAdvice source code!
By Guillaume Grussenmeyer on Nov 23, 2008 at 6:49 AM PST
Oh, ha ha ha... ugh. I'll fix that one after I'm off kid duty. :-D Thanks for the catch.
By Willie Wheeler on Nov 23, 2008 at 9:18 AM PST
OK, fixed. Thanks again Guillaume.
By Willie Wheeler on Nov 23, 2008 at 12:14 PM PST

Hi Willie.

I really like your page. Hope to find more and more articles here.

This example is nice but have one disadvantage - we will have as much threads as requests in specified time t, where t is time needed to send mail. In peak hours this can be troublesome. It would be better to have thread pool but can we do this here?

By Daniel on Jan 6, 2009 at 1:49 PM PST

Hi Daniel. Thanks for the kind words about the article. As to the disadvantage you mention—funny you mention it. We're actually putting a version of this article in the upcoming book and I had the same thought you mention. What I'm planning to do with the recipe is replace the Thread/Runnable part with Executor/Callable. Then we can do Executors.newCachedThreadPool() instead of creating threads directly. So yep, I think we're on the same page.

As to additional articles, I'll definitely be adding more. I need to get a couple of chapters written for the book but I have an article in the pipeline.

By Willie Wheeler on Jan 6, 2009 at 7:04 PM PST

Hi Willie,

Thx for reply:) Good idea! Can we see this solution also here?

By Daniel on Feb 25, 2009 at 3:22 AM PST

Hi Daniel, welcome back. That's a great idea for a quick article. I'll try to post something on that this weekend. Thanks for the suggestion!

By Willie Wheeler on Feb 25, 2009 at 7:03 AM PST

Great article! It worked perfectly using the annotation-config!!!

By Daniel Camargo on Mar 5, 2009 at 5:21 AM PST

Willie, thanks for an excellent AOP example! I've been working with Spring framework for a few months now, but I'm still quite new to AOP, and learning by working examples seems to work the best for me.

Now to my question: as you already described in your article, when sending out email, sometimes you need to do it synchronously (with feedback) and sometimes asynchronously and with the manual ways (i.e. creating a wrapper to fork new threads) it's easy to have the control.

What is the best way to do this with AOP? I'm already using my own MailSender wrapper to provide utility methods to send email and not have to deal with SimpleMailMessage etc. - one of my methods looks like this: sendMail(String to, String subject, String body). The easiest way to have 2 ways of sending (synchronous and asynchronous) would probably be to create an additional method - for example sendMailFork(String to, String subject, String body) - this would only pass the call to sendMail() - and configure the forkAdvice only for the sendMailFork methods. This way, the caller would use the sendMail methods to send email synchronously, and sendMailForked to send mail asynchronously.

But I was wondering - isn't there a better and more elegant way to achieve the same goal with AOP? Thanks for any advice in advance! :)

By Rado on Aug 6, 2009 at 12:56 AM PDT

Nice Article. good way to do modular programming, the module being the aop advice.

By G Sunderam on Oct 4, 2009 at 6:02 PM PDT

Thanks for the nice article.But my concern is whether this can be used in production environment. My problem is that the server can ran out of maximum Thread limit . Is there anyway to use Thread Pooling along with this ?

Thanks

By umanga on Oct 22, 2009 at 2:07 AM PDT

Post a comment

Comments currently suppressed due to excessive spam. I'll reinstate them later, this time with approvals turned on. :-)

Spring in Practice
My brother and I are writing Spring in Practice for Manning!

What's New?

2009-08-30 - Check out my two-part series on DZone: Spring Integration: A Hands-On Tutorial.
2009-03-25 - My new article Getting Started with Spring Batch 2.0 is available on DZone.
Home | Consulting | Tech Articles | Mailing List | Contact | Spring Blog
Copyright © 2008 Wheeler Software, LLC.