Using Spring 2.0 AOP to implement web-request interception

I was teaching another class yesterday and the focus was mostly on the web-tier. This is where we usually spend a lot of time on Spring Web MVC and Spring Web Flow and if the class is interested we also do a bit of Acegi Security (although in this half hour we’re only scratching the surface of it).

One of the subjects in the web module is using HandlerInterceptors to transparently add behavior to web requests. HandlerInterceptors are nice little components that allow you to for example do simple authentication, populate the Log4J Nested Diagnostics Context is populate the model returned by a controller with information each and every view needs (such as user information or information about the current state of the system).

When we touch on HandlerInterceptors, most of the time the audience pretty much sees the resemblance with Servlet Filters immediately. The resemblance is certainly there. There are pretty good reasons why we initially choose for a special purpose interception mechanism (Servlet Filters and EJB 2.x & 1.x transaction and security management are also good examples of special purpose interception mechanisms).

One of the guys in class asked me if it was possible to implement Spring’s HandlerInterceptor mechanism using Spring’s new AOP functionality. Interesting question! Yes in fact it’s possible and that’s what I’ll be reviewing in this post.

The traditional approach (using HandlerInterceptors)

Let’s first review a short example of how we use HandlerInterceptors to transparently do something completely orthogonal to any request in the system.


/**
* Simple handler interceptor that outputs some logging right
* before the request is executed.
*
* @author Alef Arendsen
*/
public class OldSchoolRequestMonitor implements HandlerInterceptor {

public void afterCompletion(HttpServletRequest req,
HttpServletResponse res, Object handler, Exception ex)
throws Exception {
}

public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler, ModelAndView mav)
throws Exception {
}

/**
* Here we're just implementing the preHandle method
* to output a bit of logging data *before* the request
* is handled.
*/
public boolean preHandle(HttpServletRequest request,
HttpServletResponse arg1, Object response) throws Exception {
System.out.println("Request came in (using a HandlerInterceptor now)");
return true;
}
}

This interceptor is actually pretty straightforward. Plugging it in to let it intercept requests is arguably even simpler. After we’ve created our web application infrastructure (web.xml and ***-servlet.xml file), we’re ready to put it to work:



In short, the process after we’ve added the above code to our ***-servlet.xml file is as follows:

  1. A request (/helloWorld.html for example) comes in, the DispatcherServlet picks it up
  2. Using a handler mapping, the DispatcherServlet determines the execution chain of this request (what handlers or controller are there to handle this request, are there any interceptors, et cetera)
  3. It finds there is an interceptor (the one configured alongside the HandlerMapping) and a controller (the HelloWorldController) that both match
  4. The DispatcherServlet starts to execute both in turn and that’s how the HandlerInterceptor is allowed to intercept requests

Additional features the HandlerInterceptor class has are the following:

  • - it allows modification of the request processing chain by returning true or false from the preHandle() method. If you return false, the execution will halt
  • - it allows you to modify the ModelAndView instance returned by controllers in the postHandle() method, which is pretty neat because you can do all kinds of fancy stuff there
  • - it allows you to inspect exceptions thrown from the handleRequest() method implemented by Controllers

Using simple (Spring 2.0) plain object advice

So now for the Spring 2.0 approach with plain objects and AOP. Instead of implementing the HandlerInterceptor interface, we’re going to reuse a simple object that doesn’t have any specific Spring interfaces:


public class RequestMonitor {

public void logRequest() {
System.out.println("Request came in (using a simple Spring AOP 2.0 advice now)");
}

}

So the requirement here basically is that we want to log every web request. Let’s express that using the usual (AOP) suspects. First, our pointcut:


expression="execution(* org.springframework.web.servlet.mvc.Controller+.handleRequest(..))"/>

Review this pointcut carefully and think what it actually means. How we usually explain things to people is to read the aspect as follows: a web request (notice the name of the pointcut) is the execution of the handleRequest method on any Controller.

Now we need to configure a piece of advice. Since the advice itself is a simple object, the only thing we need to do is configuring it in Spring:



Linking the advice object and the pointcut is a bit more completed, but actually not that difficult either. We want to log incoming requests before the are handled (as stated earlier in the post). So we will be using before advice. We want to call the logRequest() method as seen in the RequestMonitor class defined above. And we want to do that if the webRequest pointcut matches (in other words, for every web request):





The entire AOP configuration needs to be wrapped inside an element, but that’s just details for now. The result of the two different ways of implemented the interceptor is exactly the same, so in other words, yes, implement web-level interceptor using AOP is perfectly possible.

Somewhat more advanced advice

Of course I hear everybody saying right now: “so what about access to the request, the response, the model, et cetera)!”. Well, that’s something I won’t be able to cover in this entry, as I’m almost out of time. I’ll post a more advanced sample later this week or next week.

Conclusion

So yes, it’s possible to get basic HandlerInterceptor behavior in place with Spring AOP as well. The question of course still remains if all of the things we can do with a HandlerInterceptor are also possible using Spring AOP. We’ll see that in my next entry. We’ll also touch on the subject of whether or not this is a good thing to do.

[i] requestmonitor-1.0.zip - the sample application showing both ways of monitoring web requests (note that for the sample to work, you need to put the Spring 2 jar in the lib directory as well as the AspectJ Weaver jar. I’ve left those out, otherwise the file size would grow too big.

12 Responses to “Using Spring 2.0 AOP to implement web-request interception”


  1. 1 Erik Weibust Oct 31st, 2006 at 3:15 pm

    Nice post. I’ll be waiting for the follow-up with notes on accessing the HttpReq/HttpResp/Model.

    Erik

  2. 2 sapporo Oct 31st, 2006 at 3:58 pm

    Nice.

    Regarding the missing jars in your example download, have you thought about providing a Maven2 project? That would make it very easy to run your example, without inflating download size (assuming one has Maven2 installed).

  3. 3 Alef Oct 31st, 2006 at 11:28 pm

    Yes, this is something I definitely want to do, but haven’t had the time for it yet. I do have the Maven2 plugin installed in Eclipse, so it shouldn’t be very difficult I guess…

    I’ll try to create a POM for the next sample!

    Thanks,
    Alef

  4. 4 Spiros Tzavellas Nov 3rd, 2006 at 4:05 am

    The link to the sample application is broken.

    The correct link is requestmonitor-1.0.zip

  5. 5 Alef Nov 4th, 2006 at 2:17 pm

    Thanks Spiros for pointing this out.

    I’ve fixed the link in the post now as well.

  6. 6 Rakesh Nov 9th, 2006 at 3:26 pm

    I would love to see the code you put in the interceptor that set up the log4j ndc!

  7. 7 Riyaz Dec 8th, 2006 at 4:57 pm

    Looks Good on the HandlerInterceptor perceptive….

    Please add the complete code with handler mapping + controllers

  8. 8 Ana May 1st, 2007 at 3:15 pm

    Hi,

    What if I want to return a different JSP in the preHandle and halt the execution by returning false?

  9. 9 Jason Hitt Jul 20th, 2007 at 5:08 pm

    Bear in mind that this breaks handily if you use some of the built-in controllers like MultiActionController or SimpleFormController. You can’t advise final methods (and AbstractController declares handleRequest as final). Switching to the CGLIB version of Spring AOP may work, but as always, it isn’t recommended.

  10. 10 David Karlsen Dec 21st, 2007 at 6:00 pm

    Eagerly awaiting the next part, as I’mn facing a problem where I want to intercept all web-requests to do prehandling - and don’t want to define the HandlerInterceptor explicitly in the context. (Want it to be auto-detected by application which include it into their classpath).

  11. 11 Tilak Jun 12th, 2008 at 9:35 am

    Great post. I was practically pulling my hair until I came across this post (What I needed to do was that I had to declare the aop bean in the *-servlet.xml file to be able to intercept handleRequest call. When I had the bean declared in say aop.xml and had this file loaded as part of WebApplicationContext, I was not able to intercept the handleRequest method).

  1. 1 marouani.info » after() throwing(Exception e) : serviceMethod() { mail(e); } Pingback on Sep 16th, 2008 at 7:10 am

Leave a Reply