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.
-
The below one works to an extend. @Pointcut("execution(* (@org.rejeev.Monitor *).*(..))") However now the advice is being executed twice. Any clue? – Rejeev Divakaran Jan 06 '10 at 08:32
-
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? – Rejeev Divakaran Jan 06 '10 at 12:18
-
10You should accept the excellent answer below. This gives him reputation. There are precious few people here on SO who can answer AspectJ questions. – fool4jesus Nov 12 '13 at 17:38
10 Answers
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.

- 10,545
- 5
- 33
- 39
-
1Thanks. The discussion of Annotation pointcuts on your Cheat Sheet is particularly useful. – GregHNZ Feb 07 '13 at 22:11
-
1How do I get reference to the class in the advice the way I do with normal pointcut advices is @Before("onObjectAction() && this(obj)") – Priyadarshi Kunal Jul 29 '13 at 07:35
-
The Cheat Sheet was very helpful, even though it's been 5 years :) – Yadu Krishnan Feb 19 '15 at 13:16
-
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 http://stackoverflow.com/questions/37583539/aspectj-before-not-logging-two-methods-from-same-class, because this is not happening in my case. – HVT7 Jun 02 '16 at 06:18
-
I feel execution public is redundant because you can't have a pointcut on private methods – amstegraf Apr 24 '20 at 14:32
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>

- 5,909
- 2
- 35
- 25
-
1Nice example. One question: why does the Annotation `Monitor` have to be a Spring `Component`? – mwhs Nov 22 '13 at 16:36
-
1The `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`. – Alex Nov 22 '13 at 20:46
-
1Ok Thanks. But I was talking about the `@Component` annotation on the `@interface` not the `Aspect`. Why is that needed? – mwhs Nov 23 '13 at 19:18
-
2The `@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. http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/aop.html – Alex Nov 25 '13 at 01:39
-
Does this do only "public" methods in the annotated classes or does it do all the methods (no matter what access level)? – Lee Meador Apr 20 '15 at 20:25
-
I am pretty sure you can intercept private methods as well. What really happens is that AspectJ rewrites the class. – Alex Apr 23 '15 at 12:57
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.

- 588,226
- 146
- 1,060
- 1,140
Use
@Before("execution(* (@YourAnnotationAtClassLevel *).*(..))")
public void beforeYourAnnotation(JoinPoint proceedingJoinPoint) throws Throwable {
}

- 2,094
- 26
- 27
You can also define the pointcut as
public pointcut publicMethodInsideAClassMarkedWithAtMonitor() : execution(public * (@Monitor *).*(..));

- 5,771
- 10
- 42
- 48
I share with you a code that can be useful, it is to create an annotation that can be used either in a class or a method.
@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Documented
public @interface AnnotationLogger {
/**
* It is the parameter is to show arguments in the method or the class.
*/
boolean showArguments() default false;
}
@Aspect
@Component
public class AnnotationLoggerAspect {
@Autowired
private Logger logger;
private static final String METHOD_NAME = "METHOD NAME: {} ";
private static final String ARGUMENTS = "ARGS: {} ";
@Before(value = "@within(com.org.example.annotations.AnnotationLogger) || @annotation(com.org.example.annotations.AnnotationLogger)")
public void logAdviceExecutionBefore(JoinPoint joinPoint){
CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
AnnotationLogger annotationLogger = getAnnotationLogger(joinPoint);
if(annotationLogger!= null) {
StringBuilder annotationLoggerFormat = new StringBuilder();
List<Object> annotationLoggerArguments = new ArrayList<>();
annotationLoggerFormat.append(METHOD_NAME);
annotationLoggerArguments.add(codeSignature.getName());
if (annotationLogger.showArguments()) {
annotationLoggerFormat.append(ARGUMENTS);
List<?> argumentList = Arrays.asList(joinPoint.getArgs());
annotationLoggerArguments.add(argumentList.toString());
}
logger.error(annotationLoggerFormat.toString(), annotationLoggerArguments.toArray());
}
}
private AnnotationLogger getAnnotationLogger(JoinPoint joinPoint) {
AnnotationLogger annotationLogger = null;
try {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = joinPoint.getTarget().getClass().
getMethod(signature.getMethod().getName(), signature.getMethod().getParameterTypes());
if (method.isAnnotationPresent(AnnotationLogger.class)){
annotationLogger = method.getAnnotation(AnnotationLoggerAspect.class);
}else if (joinPoint.getTarget().getClass().isAnnotationPresent(AnnotationLoggerAspect.class)){
annotationLogger = joinPoint.getTarget().getClass().getAnnotation(AnnotationLoggerAspect.class);
}
return annotationLogger;
}catch(Exception e) {
return annotationLogger;
}
}
}

- 890
- 3
- 17
- 38
The simplest way seems to be :
@Around("execution(@MyHandling * com.exemple.YourService.*(..))")
public Object aroundServiceMethodAdvice(final ProceedingJoinPoint pjp)
throws Throwable {
// perform actions before
return pjp.proceed();
// perform actions after
}
It will intercept execution of all methods specifically annotated with '@MyHandling' in 'YourService' class. To intercept all methods without exception, just put the annotation directly on the class.
No matter of the private / public scope here, but keep in mind that spring-aop cannot use aspect for method calls in same instance (typically private ones), because it doesn't use the proxy class in this case.
We use @Around advice here, but it's basically the same syntax with @Before, @After or any advice.
By the way, @MyHandling annotation must be configured like this :
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyHandling {
}

- 3,486
- 3
- 32
- 38
-
-
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 ? – Donatello May 24 '12 at 12:26
-
The `// perform actions after` will never get called since we're returning the value in the line before. – josephpconley Apr 21 '17 at 15:34
From Spring's AnnotationTransactionAspect
:
/**
* Matches the execution of any public method in a type with the Transactional
* annotation, or any subtype of a type with the Transactional annotation.
*/
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *);

- 7,336
- 6
- 55
- 85
You could use Spring's PerformanceMonitoringInterceptor and programmatically register the advice using a beanpostprocessor.
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Monitorable
{
}
public class PerformanceMonitorBeanPostProcessor extends ProxyConfig implements BeanPostProcessor, BeanClassLoaderAware, Ordered,
InitializingBean
{
private Class<? extends Annotation> annotationType = Monitorable.class;
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private Advisor advisor;
public void setBeanClassLoader(ClassLoader classLoader)
{
this.beanClassLoader = classLoader;
}
public int getOrder()
{
return LOWEST_PRECEDENCE;
}
public void afterPropertiesSet()
{
Pointcut pointcut = new AnnotationMatchingPointcut(this.annotationType, true);
Advice advice = getInterceptor();
this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
}
private Advice getInterceptor()
{
return new PerformanceMonitoringInterceptor();
}
public Object postProcessBeforeInitialization(Object bean, String beanName)
{
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
{
if(bean instanceof AopInfrastructureBean)
{
return bean;
}
Class<?> targetClass = AopUtils.getTargetClass(bean);
if(AopUtils.canApply(this.advisor, targetClass))
{
if(bean instanceof Advised)
{
((Advised)bean).addAdvisor(this.advisor);
return bean;
}
else
{
ProxyFactory proxyFactory = new ProxyFactory(bean);
proxyFactory.copyFrom(this);
proxyFactory.addAdvisor(this.advisor);
return proxyFactory.getProxy(this.beanClassLoader);
}
}
else
{
return bean;
}
}
}

- 21
- 1