Thursday, January 28, 2010

Spring 3.0 and <mvc:annotation-driven />

I have used Struts1 and Struts2 extensively for years.  With that background, I can appreciate some of the things that Spring-MVC brings to the table such as Dependency Injection, clean integration with Bean Validator (JSR-303), smooth Integration with different View Technologies, among others. Furthermore,  Spring-MVC has been making improvements through out each release that has made it a more robust framework, including the latest REST support. Like every framework, there is always a "gotcha" in a feature and such is the case for <mvc:annotation-driven />.

<mvc:annotation-driven /> is a nice feature, however depending on how you are used to organize your Spring-MVC files, it can prove to be confusing. I'll try to explain my findings as clear as I can.

As you know, Spring-MVC will expect a <servlet-name>-servlet.xml Spring configuration in the WEB-INF (unless configured otherwise in web.xml). If you also load an application context via Spring's RequestContextListener (hereto known as the root WebApplicationContext), the servlet XML (WebApplicationContext) will inherit the beans from the root context.  Although this is a known fact, the problem comes when the servlet XML is not able to read any @RequestMapping metadata from beans (@Controller objects) detected in the root WebApplication Context. The logs clearly show that the beans are detected, but not the metadata.

This means that in order to use <mvc:annotation-driven /> you have two choices:
  1. The servlet XML now needs to contain <mvc:annotation-driven /> and be able to detect the @Controller objects so it can refer to the metadata in those controllers to use (e.g. via <context:component-scan /> ). All these within the same XML file or via imports.
  2. The root XML needs to have the declarations as mentioned above (<mvc:annotation-driven /> and <context:component-scan />).
I prefer to use the first one, and make my scan reach only the packages that are specific to the design of your servlet, however I can see how option 2 may be a more compelling option for small applications. Interestingly enough, that's how all sample applications using <mvc:annotation-driven /> are configured.

For further reading of this new features, take a look at JIRA issue SPR-6524 where Jurgen Hoeller and Keith Donald explain their thoughts on why <mvc:annotation-driven /> is supposed to behave like this.

Hopefully this helps some!

No comments: