Saturday, July 7, 2007

Spring MVC: How it works

If you are interested in the Spring Framework’s MVC packages, this could be helpful. It’s a unified description of the lifecycle of a web application or portlet request as handled by Spring Web MVC and Spring Portlet MVC. I created this for two reasons: I wanted a quick reference to the way Spring finds handlers for each stage of the request; and I wanted a unified view so I could see the similarities and differences between Web MVC and Portlet MVC.
Spring Web MVC, part of the Spring Framework, has long been a highly-regarded web application framework. With the recent release of Spring 2.0, Spring now supports portlet development with the Spring Portlet MVC package. Portlet MVC builds on Web MVC; even their documentation is similar. My focus right now is on portlet development, and I found it cumbersome to have to read the Web MVC and Portlet MVC documentation simultaneously. So I have re-edited the two together into one unified document. I have also included related information from elsewhere in the documentation, so it’s all in one place.
My idea here is to make it easy to go through your Spring configuration files and ensure that all beans are declared and named as they should be, whether you are using Spring Web MVC or Spring Portlet MVC.

Dispatcher

Spring’s Web and Portlet MVC are request-driven web MVC frameworks, designed around a servlet or portlet that dispatches requests to controllers. Spring’s dispatchers (DispatcherServlet and DispatcherPortlet) are also completely integrated with the Spring ApplicationContext and allow you to use every other feature Spring has.
The DispatcherServlet is a standard servlet (extending HttpServlet), and as such is declared in the web.xml of your web application. Requests that you want the DispatcherServlet to handle should be mapped using a URL mapping in the same web.xml file. Similarly, the DispatcherPortlet is a standard portlet (extending GenericPortlet), and as usual is declared in the portlet.xml of your web application. This is all standard J2EE configuration; Here are a couple of examples:
From web.xml:
<web-app>
    <servlet>
        <servlet-name>example</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
 <!-- all requests ending with ".form" will be handled by Spring. -->
    <servlet-mapping>
        <servlet-name>example</servlet-name>
        <url-pattern>*.form</url-pattern>
    </servlet-mapping>
</web-app>
From portlet.xml:
<portlet>
 <portlet-name>sample</portlet-name>
 <portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
 <supports>
  <mime-type>text/html</mime-type>
  <portlet-mode>view</portlet-mode>
 </supports>
 <portlet-info>
  <title>Sample Portlet</title>
 </portlet-info>
</portlet>
In the Portlet MVC framework, each DispatcherPortlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext. These inherited beans can be overridden in the portlet-specific scope, and new scope-specific beans can be defined local to a given portlet instance.

Dispatcher Workflow

When a DispatcherServlet or DispatcherPortlet is set up for use and a request comes in for that specific dispatcher, it starts processing the request. The sections below describe the complete process a request goes through when handled by such a dispatcher, from determining the application context right through to rendering the view.

Application context

For Web MVC only, the WebApplicationContext is searched for and bound in the request as an attribute in order for the controller and other elements in the process to use. It is bound by default under the key DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE.

Locale

The locale is bound to the request to let elements in the process resolve the locale to use when processing the request (rendering the view, preparing data, etc.). For Web MVC, this is the locale resolver. For Portlet MVC, this is the locale returned by PortletRequest.getLocale(). Note that locale resolution is not supported in Portlet MVC - this is in the purview of the portal/portlet-container and are not appropriate at the Spring level. However, all mechanisms in Spring that depend on the locale (such as internationalization of messages) will still function properly because DispatcherPortlet exposes the current locale in the same way as DispatcherServlet.

Theme

For Web MVC only, the theme resolver is bound to the request to let elements such as views determine which theme to use. The theme resolver does not affect anything if you don’t use it, so if you don’t need themes you can just ignore it. Theme resolution is not supported in Portlet MVC - this areas is in the purview of the portal/portlet-container and is not appropriate at the Spring level.

Multipart form submissions

For Web MVC and for Portlet MVC Action requests, if a multipart resolver is specified, the request is inspected for multiparts. If they are found, the request is wrapped in a MultipartHttpServletRequest or MultipartActionRequest for further processing by other elements in the process.

Handler mapping

Spring looks at all handler mappings (beans implementing the appropriate HandlerMapping interface) in the application context. Any that implement the Ordered interface are sorted (lowest order first), and others are added at the end of the list. The handler mappingas re tried in order until one yields a handler. (Note: if the dispatcher’s detectAllHandlerMappings attribute is set to false, then this changes: Spring simply uses the handler mapping bean called “handlerMapping” and ignores any others.)

Handler

If a handler is found, the execution chain associated with the handler (pre-processors, controllers and post-processors) will be executed in order to prepare a model for rendering. THe handler chain returns a View object or a view name, and normally also returns a model. For example, a pre-processor may block the request for security reasons and render its own view; in this case it will not return a model. Note that tha handler chain need not explicitly return a view or view name. If it does not, Spring creates a view name from the request path. For example, the path /servlet/apac/NewZealand.jsp yeilds the view name “apac/NewZealand”. This behaviour is implemented by an implicitly-defined DefaultRequestToViewNameTranslator bean; you can configure your own bean (which must be called “viewNameTranslator”) if you want to customise its behaviour.

Exceptions

Exceptions that are thrown during processing of the request go to the hander exception resolver chain. Spring looks at all hander exception resolver (beans implementing the appropriate HandlerExceptionResolverinterface) in the application context. Any that implement the Ordered interface are sorted (lowest order first), and others are added at the end of the list. The resolvers re tried in order until one yields a model and view. (Note: if the dispatcher’s detectAllHandlerExceptionResolvers attribute is set to false, then this changes: Spring simply uses the hander exception resolver bean called “handlerExceptionResolver” and ignores any others.)

View resolver

If the handle chain returns a view name and a model, Spring uses the configured view resolvers to resolve the view name to a View. Spring looks at all view resolvers (beans implementing the ViewResolver interface) in the application context. Any that implement the Ordered interface are sorted (lowest order first), and others are added at the end of the list. Then view resolvers are tried in order until one yields a view. (Note: if the dispatcher’s detectAllViewResolvers attribute is set to false, then this changes: Spring simply uses the view resolver bean called “viewResolver” and ignores any others.) If the handle chain returns a View object, then no view resolution is necessary. Similarly, if it does not return a model, then no view will be rendered, so again no view resolution is necessary.

View

If we now have a view and a model, then Spring uses the view to render the model. This is what the user will see in the browser window or portlet.

No comments: