@AspectJ pointcut for all methods of a class with specific annotation

167,969

Solution 1

You should combine a type pointcut with a method pointcut.

These pointcuts will do the work to find all public methods inside a class marked with an @Monitor annotation:

@Pointcut("within(@org.rejeev.Monitor *)")
public void beanAnnotatedWithMonitor() {}

@Pointcut("execution(public * *(..))")
public void publicMethod() {}

@Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
public void publicMethodInsideAClassMarkedWithAtMonitor() {}

Advice the last pointcut that combines the first two and you're done!

If you're interested, I have written a cheat sheet with @AspectJ style here with a corresponding example document here.

Solution 2

Using annotations, as described in the question.

Annotation: @Monitor

Annotation on class, app/PagesController.java:

package app;
@Controller
@Monitor
public class PagesController {
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public @ResponseBody String home() {
        return "w00t!";
    }
}

Annotation on method, app/PagesController.java:

package app;
@Controller
public class PagesController {
    @Monitor
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public @ResponseBody String home() {
        return "w00t!";
    }
}

Custom annotation, app/Monitor.java:

package app;
@Component
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Monitor {
}

Aspect for annotation, app/MonitorAspect.java:

package app;
@Component
@Aspect
public class MonitorAspect {
    @Before(value = "@within(app.Monitor) || @annotation(app.Monitor)")
    public void before(JoinPoint joinPoint) throws Throwable {
        LogFactory.getLog(MonitorAspect.class).info("monitor.before, class: " + joinPoint.getSignature().getDeclaringType().getSimpleName() + ", method: " + joinPoint.getSignature().getName());
    }

    @After(value = "@within(app.Monitor) || @annotation(app.Monitor)")
    public void after(JoinPoint joinPoint) throws Throwable {
        LogFactory.getLog(MonitorAspect.class).info("monitor.after, class: " + joinPoint.getSignature().getDeclaringType().getSimpleName() + ", method: " + joinPoint.getSignature().getName());
    }
}

Enable AspectJ, servlet-context.xml:

<aop:aspectj-autoproxy />

Include AspectJ libraries, pom.xml:

<artifactId>spring-aop</artifactId>
<artifactId>aspectjrt</artifactId>
<artifactId>aspectjweaver</artifactId>
<artifactId>cglib</artifactId>

Solution 3

Something like that:

@Before("execution(* com.yourpackage..*.*(..))")
public void monitor(JoinPoint jp) {
    if (jp.getTarget().getClass().isAnnotationPresent(Monitor.class)) {
       // perform the monitoring actions
    }
}

Note that you must not have any other advice on the same class before this one, because the annotations will be lost after proxying.

Solution 4

Use

@Before("execution(* (@YourAnnotationAtClassLevel *).*(..))")
    public void beforeYourAnnotation(JoinPoint proceedingJoinPoint) throws Throwable {
}

Solution 5

it should be enough to mark your aspect method like this:

@After("@annotation(com.marcot.CommitTransaction)")
    public void after() {

have a look at this for a step by step guide on this.

Share:
167,969
user1098001
Author by

user1098001

Software Programmer

Updated on July 08, 2022

Comments

  • user1098001
    user1098001 almost 2 years

    I want to monitor all public methods of all Classes with specified annotation (say @Monitor) (note: Annotation is at class level). What could be a possible pointcut for this? Note: I am using @AspectJ style Spring AOP.

    • user1098001
      user1098001 over 14 years
      The below one works to an extend. @Pointcut("execution(* (@org.rejeev.Monitor *).*(..))") However now the advice is being executed twice. Any clue?
    • user1098001
      user1098001 over 14 years
      Another point is that the @Monitor annotation is on an interface and there a class implements that. Does the presence of a interface and class will cause double execution of such advice?
    • fool4jesus
      fool4jesus over 10 years
      You should accept the excellent answer below. This gives him reputation. There are precious few people here on SO who can answer AspectJ questions.
  • Alex
    Alex about 12 years
    that is not answering the original statement, with ElementType.Type
  • Donatello
    Donatello almost 12 years
    yes, ElementType.TYPE will also allow to put annotation directly on classes, which I suppose, will result to handle any method in this class. Am i true ? Is it really working ?
  • GregHNZ
    GregHNZ over 11 years
    Thanks. The discussion of Annotation pointcuts on your Cheat Sheet is particularly useful.
  • Priyadarshi Kunal
    Priyadarshi Kunal almost 11 years
    How do I get reference to the class in the advice the way I do with normal pointcut advices is @Before("onObjectAction() && this(obj)")
  • mwhs
    mwhs over 10 years
    Nice example. One question: why does the Annotation Monitor have to be a Spring Component?
  • Alex
    Alex over 10 years
    The Component annotation is used to tell the Spring container to apply include the class in the AspectJ weaver thing. By default, Spring only looks at Controller, Service, and other specific annotations, but not Aspect.
  • mwhs
    mwhs over 10 years
    Ok Thanks. But I was talking about the @Component annotation on the @interface not the Aspect. Why is that needed?
  • Alex
    Alex over 10 years
    The @Component annotation makes it so Spring will compile it with the AspectJ IoC/DI aspect-oriented system. I don't know how to say it differently. docs.spring.io/spring/docs/3.2.x/spring-framework-reference/‌​…
  • xmedeko
    xmedeko over 9 years
    Little simpler execution(public * @Monitor *.*(..)) works, too.
  • Yadu Krishnan
    Yadu Krishnan about 9 years
    The Cheat Sheet was very helpful, even though it's been 5 years :)
  • Lee Meador
    Lee Meador about 9 years
    Does this do only "public" methods in the annotated classes or does it do all the methods (no matter what access level)?
  • Alex
    Alex about 9 years
    I am pretty sure you can intercept private methods as well. What really happens is that AspectJ rewrites the class.
  • HVT7
    HVT7 almost 8 years
    Just a question here, if two methods that are in hierarchy and both fall under the pointcut and belong to same class, will this execute on both? If Yes, then see stackoverflow.com/questions/37583539/…, because this is not happening in my case.
  • josephpconley
    josephpconley about 7 years
    The // perform actions after will never get called since we're returning the value in the line before.
  • amstegraf
    amstegraf about 4 years
    I feel execution public is redundant because you can't have a pointcut on private methods