|
|
Using custom annotations with Spring AOP
I am developing a web application that uses Spring MVC, Spring Services and Spring AOP. As a part of that, there is a logging aspect using Spring AOP that has before, afterReturning and afterThrowing methods. Also, there are few custom method-level annotations such as @DoNotLog and @LogExceptionAsWarning that I want to use in the aspect to see if logging should be done and if an exception should be logged as a warning. I tried to check for these annotations at run time using isAnnotationPresent method on a quot;Methodquot; object, but it does not work.
It seems to me that as the objects generated by Spring are proxy objects and not the objects that I have coded, the annotations declared on these methods are lost during aspect weaving. However, the weird part is that, during logging, it does show entries for the classes that I have coded.
Looking forward to advise.
Hi
I think you should try to include your annotation in the pointcut definition itself. Since Spring 2.0 you can use the @AspectJ style to declare your aspects.
Here is a someway contrived example, but hope it helps.
I have an After Throwing Adivce which handles exceptions from the application and sends them via email to a receiver.Code:
@Aspect
public class MailNotificationAspect {
private Mailer mailer;
public void setMailer(Mailer mailer) {
this.mailer = mailer;
}
@Pointcut(quot;execution(* *.*(..)) amp;amp; @within(com.trivadis.issuesmgmt.aop.Mail) amp;amp; @annotation(m) quot;)
public void inApplication(Mail m) {}
@AfterThrowing(pointcut=quot;inApplication(m)quot;,throwing=quot;exquot;)
public void afterThrowingWithSubject(Exception ex, Mail m) throws Throwable {
mailer.send(ex, m.subject());
}
}
Here is a service which throws an exception if the paramter is null.Code:
@Mail
public class PersonMgmtServiceImpl implements PersonMgmtService
{
...
@Mail(subject=quot;This is the test subjectquot;)
public void createPerson(Person person) throws ApplicationException {
if (person == null) {
throw new ApplicationException();
}
personDAO.save(person);
}
...
With the annotation Mail on class level, I specify that a mail should be sent whenever a method in the class throws an exception and with the annotation on method level I can overwrite the subject being used in the mail message.
the imporant part in the aspect above is the pointcut declaration:
@Pointcut(quot;execution(* *.*(..)) amp;amp; @within(com.trivadis.issuesmgmt.aop.Mail) amp;amp; @annotation(m) quot;)
public void inApplication(Mail m) {}
This reads as quot;all executions of any @Mail annotated methods where the declared type of the target object (the class) has an @Mail annotationquot;.
By using @annotation(m) I'm using the binding form and bind it as a parameter to the advice
@AfterThrowing(pointcut=quot;inApplication(m)quot;,throwin g=quot;exquot;)
public void afterThrowingWithSubject(Exception ex, Mail m) throws Throwable {
mailer.send(ex, m.subject());
}
Hope this helps.
One last thing you need to be aware of. Annotations on methods are not inherited, so if your on class level, you won't see a method-level annotation defined in an interface. |
|