Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring 3 MVC @Controller with AOP interceptors?

Anyone knows why apparently it is not possible to use AOP with annotated MVC Controllers? (see Post). I have a @Controller that stops working as soon as I add a pointcut to it. The problem is not that the interceptor is not being called, but rather the @Controller simply stops working (in the log you can see that instead of "Mapped URL path [/xx] onto handler 'Yyy'" you get a "no URL paths identified").

I know there is a mechanism for adding interceptors to controllers via the handlerMapping but my question is specific to AOP interceptors. Aren't annotated controllers just pojos in the Spring container as any other pojo? What is the difference? Why?

@Controller
@RequestMapping("/user")
public class RestTestImpl implements RestTest {
    @RequestMapping(value="/", method={RequestMethod.GET})
    public @ResponseBody String deleteUsers(String arg) {
        return "Xxxxx";
    }
}

In my servlet-Context I have:

<context:component-scan base-package="org.xxx.yyy"></context:component-scan>
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    . . .
</bean>

And everything works just great.

But when I add:

    <aop:config>
        <aop:pointcut expression="execution(* org.xxx.*(..))" id="pc1"/>
        <aop:advisor advice-ref="hibernateInterceptor"  pointcut-ref="pc1" order="2" />
    </aop:config>

The controller stops being a controller (no errors, simply it stops binding to the specified URL)!

like image 610
pakman Avatar asked May 02 '11 22:05

pakman


3 Answers

From the Spring MVC Reference:

Note
When using controller interfaces (e.g. for AOP proxying), make sure to consistently put all your mapping annotations - such as @RequestMapping and @SessionAttributes - on the controller interface rather than on the implementation class.

Granted, this note is well hidden :-)

like image 62
Sean Patrick Floyd Avatar answered Oct 18 '22 21:10

Sean Patrick Floyd


I ran into the same issue and found out the solution.

Indeed your controller (annotated by @Controller) and your aspects (annotated by @Aspect) should be in the same Spring context.

Usually people define their controllers in the dispatch-servlet.xml or xxx-servlet.xml and their service beans (including the aspects) in the main applicationContext.xml. It will not work.

When Spring initializes the MVC context, it will create a proxy for your controller but if your aspects are not in the same context, Spring will not create interceptors for them.

The above ssertion does not depend

  • on the way your declare your controllers/aspects (by manual XML declaration or annotation style)
  • on the proxying style you choose (JDK proxy or CGLIB)

I've tested all the combinations and they all work as long as the controller & aspects are in the same Spring context

like image 16
doanduyhai Avatar answered Oct 18 '22 22:10

doanduyhai


My best guess without doing some serious digging is because Spring's AOP mechanism that you are using is wrapping the target classes in proxy classes which end up loosing their annotation or the original annotation gets dropped after weaving.

I am sure there is a better answer and I'll expand on mine as I think of a better more clear way to present it.

like image 1
Andrew White Avatar answered Oct 18 '22 22:10

Andrew White