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) {
No comments:
Post a comment