14

I want to run some code before every method in a Spring (3.2.3) @Controller. I have the following defined but it won't run. I suspect the pointcut expression is incorrect.

dispatcher-servlet.xml

<aop:aspectj-autoproxy/>
<bean class="com.example.web.controllers.ThingAspect"/>

c.e.w.c.ThingAspect

@Pointcut("execution(com.example.web.controllers.ThingController.*(..))")
public void thing() {
}

@Before("thing()")
public void doStuffBeforeThing(JoinPoint joinPoint) {
    // do stuff here
}
VedantK
  • 9,728
  • 7
  • 66
  • 71
Goose
  • 802
  • 1
  • 10
  • 22
  • 1
    Maybe a [`@ControllerAdvice`](http://docs.spring.io/spring/docs/4.0.3.RELEASE/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html) is what you are looking for. – Markus Malkusch May 12 '14 at 11:41
  • Is it (a) not running at all or (b) not running for some methods? This would help diagnose your issue. – Phil Haigh May 12 '14 at 12:02
  • I didn't know ControllerAdvice existed but looking at the documentation it is for attaching ExceptionHandler, InitBinder, and ModelAttribute to several controllers. I was looking for something to run before every method which in my case are all RequestMapping annotated methods. At the moment the Aspect is not being called at all for any methods. I could use a Spring Interceptor but AOP seemed ideally suited to the task. – Goose May 12 '14 at 13:11
  • I had forgotten to annotate my aspect class with (at)Aspect. @kriegaex did however spot something else that stopped it from working anyway. Thanks for your help. – Goose May 12 '14 at 23:16
  • For folks on older version of Spring MVC ( like 3.1 or so ) , refer [this](http://forum.spring.io/forum/spring-projects/aop/22178-using-aspect-on-class-that-extends-simpleformcontroller) too as I was stuck for sometime while trying to introduce profiling for form controllers in a very old code base. – Sabir Khan Sep 18 '18 at 11:09

3 Answers3

14

Your pointcut expression is missing a return type like void, String or *, e.g.

execution(* com.example.web.controllers.ThingController.*(..))
kriegaex
  • 63,017
  • 15
  • 111
  • 202
8

The correct way to do it in current versions of Spring MVC is through a ControllerAdvice.
See: Advising controllers with the @ControllerAdvice annotation

For previous versions, refer to this answer of mine: https://stackoverflow.com/a/5866960/342852

Community
  • 1
  • 1
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • 2
    @kaqqao I disagree, `@ControllerAdvice` only has a specific set of possibilities. You could possibly intercept every `@RequestMapping` method using `@ModelAttribute`, but you'd only have the context of the `Model` and nothing else. I think you should upvote @geoand, although I haven't looked at Spring MVC interceptors, I believe `ControllerAdvice` is not powerful enough. – froginvasion Jan 15 '16 at 09:59
  • @geoand answer is indeed good and I have upvoted it just now. Still, the question didn't really say much out about the specifics, just that something should run before each method and `@ControllerAdvice` does that... – kaqqao Jan 15 '16 at 14:30
  • 1
    they both do different things. Interceptors are for cross-cutting concerns, `@ControllerAdvice` is for providing model enrichers and exception handlers – Sean Patrick Floyd Jan 15 '16 at 15:14
  • @ControllerAdvice is not meant for addressing cross-cutting concerns. The correct method is given in the accepted answer. Downvoting, – saran3h Apr 07 '22 at 05:43
2

Besides @ControllerAdvice that is already mentioned in another answer, you should check out Spring MVC interceptors.

They basically simplify AOP for controllers and can be used in cases where @ControllerAdvice doesn't give you enough power.

froginvasion
  • 833
  • 6
  • 19
geoand
  • 60,071
  • 24
  • 172
  • 190
  • Except, sadly it seems not possible to get controller method parameter values through the interceptor. See https://stackoverflow.com/questions/39039695 – vadipp Jan 28 '22 at 08:58