@AspectJ pointcut for all methods of a class with specific annotation
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.
Comments
-
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 over 14 yearsThe below one works to an extend. @Pointcut("execution(* (@org.rejeev.Monitor *).*(..))") However now the advice is being executed twice. Any clue?
-
user1098001 over 14 yearsAnother 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 over 10 yearsYou should accept the excellent answer below. This gives him reputation. There are precious few people here on SO who can answer AspectJ questions.
-
-
Alex about 12 yearsthat is not answering the original statement, with ElementType.Type
-
Donatello almost 12 yearsyes, 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 over 11 yearsThanks. The discussion of Annotation pointcuts on your Cheat Sheet is particularly useful.
-
Priyadarshi Kunal almost 11 yearsHow do I get reference to the class in the advice the way I do with normal pointcut advices is @Before("onObjectAction() && this(obj)")
-
mwhs over 10 yearsNice example. One question: why does the Annotation
Monitor
have to be a SpringComponent
? -
Alex over 10 yearsThe
Component
annotation is used to tell the Spring container to apply include the class in the AspectJ weaver thing. By default, Spring only looks atController
,Service
, and other specific annotations, but notAspect
. -
mwhs over 10 yearsOk Thanks. But I was talking about the
@Component
annotation on the@interface
not theAspect
. Why is that needed? -
Alex over 10 yearsThe
@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 over 9 yearsLittle simpler
execution(public * @Monitor *.*(..))
works, too. -
Yadu Krishnan about 9 yearsThe Cheat Sheet was very helpful, even though it's been 5 years :)
-
Lee Meador about 9 yearsDoes this do only "public" methods in the annotated classes or does it do all the methods (no matter what access level)?
-
Alex about 9 yearsI am pretty sure you can intercept private methods as well. What really happens is that AspectJ rewrites the class.
-
HVT7 almost 8 yearsJust 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 about 7 yearsThe
// perform actions after
will never get called since we're returning the value in the line before. -
amstegraf about 4 yearsI feel execution public is redundant because you can't have a pointcut on private methods