Lives in the UK. Likes blogging, cycling and eating lemon drizzle cake. Roger is a DZone MVB and is not an employee of DZone and has posted 143 posts at DZone. You can read more from them at their website. View Full User Profile

Using Spring's AspectJ Support and the @Before Annotation

09.23.2011
| 11795 views |
  • submit to reddit

You may have wondered how the Guys at Spring do all that jiggery-pokery with the annotations that you add to your Spring beans. I’m not an expert here, but I suspect that somewhere along the way, they do a little Aspect Oriented Programming using AspectJ - after all, they do have comprehensive support for it. This of course is total supposition - I’ve not been trawling through their source code. This blog demonstrates how you can use AspectJ to intercept your class's annotated methods and to do that,I’m going to demonstrate the @Before annotation by writing a Before Advice class that takes a peak at the attributes of a method’s annotations. This blogs builds on my previous AspectJ blog that demonstrates how to write an After Throwing advice.

The first thing we really need is an annotation. Any thing will do, and I’ve written a simple @TestAnnotation as demonstrated below. This has one attribute: value:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TestAnnotation {
  String value();
}
This annotation can then be applied to any method in your application - choose one at random here as the annotation doesn’t really do anything:

public class MySimplePrintln {

  /**
   * Print a message
   */
  @TestAnnotation(value = "Roger")
  public void println(String arg0) {
    System.out.println(arg0);
  }
}

The next class is the heart of the matter. It’s a Before Advice that checks the execution of any method which is annotated with @TestAnnotation as demonstrated in the snippet below:
  @Before("execution(* *.*(..)) && @annotation(testAnnotation) ")
  public void myBeforeLogger(JoinPoint joinPoint, TestAnnotation testAnnotation) {

My previous blog explored the execution() expression in detail; however, the thing to note here is that it’s combined with the annotation expression: @annotation(testAnnotation) so as create the correct method filtering. The next thing to note is that the annotation is passed to the myBeforeLogger(..) as an argument. This allows us to get hold of the annotation’s attributes as demonstrated in the complete method source code below:

@Aspect
public class BeforeAdvice {

  // Obtain a suitable logger.
  private static Log logger = LogFactory.getLog(BeforeAdvice.class);

  @Before("execution(* *.*(..)) && @annotation(testAnnotation) ")
  public void myBeforeLogger(JoinPoint joinPoint, TestAnnotation testAnnotation) {

    System.out.println("Okay - we're in the before handler...");
    System.out.println("The test annotation value is: " + testAnnotation.value());

    Signature signature = joinPoint.getSignature();
    String methodName = signature.getName();
    String stuff = signature.toString();
    String arguments = Arrays.toString(joinPoint.getArgs());
    logger.info("Write something in the log... We are just about to call method: "
        + methodName + " with arguments " + arguments + "\nand the full toString: "
        + stuff);

  }

}

So, not only can you access a method’s arguments before it’s called, you can also access its annotation’s attributes, which to me seems a pretty powerful tool.

You’ll also need a Spring config file and some code to load it, but I’ve covered that in my previous blog on Spring and AspectJ, so take a look here for more information. The only key point here is that you need to include the line:

<aop:aspectj-autoproxy/>

...somewhere in your config file.

Running this code above will produce the following output:

This is the before handler
13:54:10,110  INFO FileSystemXmlApplicationContext:456 - Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@7a3570b0: startup date [Wed Aug 17 13:54:10 BST 2011]; root of context hierarchy
13:54:10,262  INFO XmlBeanDefinitionReader:315 - Loading XML bean definitions from file [/Java_Projects2/Tips/marin-tips-spring-3/src/main/resources/example10_beforeadvice.xml]
13:54:10,939  INFO DefaultListableBeanFactory:555 - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@30296f76: defining beans [org.springframework.aop.config.internalAutoProxyCreator,beforeHandler,mainClass,println]; root of factory hierarchy
Okay - we're in the before handler...
The test annotation value is: Roger
13:54:11,790  INFO BeforeAdvice:43 - Write something in the log... We are just about to call method: println with arguments [Something to print...]
and the full toString: void example_10_annotations.before_annotation_annotation.MySimplePrintln.println(String)
Something to print...
the end...

Finally, there’s more. Given that the @Before’s default attribute is an expression, you can apply more than one annotation to your advice method:

  @Before("execution(* *.*(..)) && @annotation(testAnnotation) @annotation(requestMethod)")
  public void myBeforeLogger(JoinPoint joinPoint, TestAnnotation testAnnotation,
      RequestMethod requestMethod) {

 

From http://www.captaindebug.com/2011/09/using-springs-aspectj-support-and.html

Published at DZone with permission of Roger Hughes, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Mohan Ambalavanan replied on Fri, 2011/09/23 - 6:02am

For me the most brilliant feature of Spring is AOP than Dependency injection, I havent seen any enterprise project realizing this feature and using AOP effectively...Hope ur post helps :) .... Gr8 post

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.