Now that you understand the WebApplicationContext and the DispatcherServlet, let's take a more detailed look at the flow that's involved with an incoming request. The flow is graphically explained in Figures 12-4 and 12-5. We'll do that using two flow diagrams. All concepts mentioned in the diagrams will be discussed in the next couple of sections.
The first phase involves determination of the path of execution by a handler mapping. The path of execution consists of zero or more interceptors and exactly one handler.
A handler is the component actually handling the request — in other words, taking appropriate action, considering the request. More specifically, it's the component that prepares the model.
The terms handler and controller are often used interchangeably. If you're usingSpring's controller infrastructure there won't be any real difference between the two. In rare cases, however, you might have to plug in your own handler infrastructure. The important thing to remember is that controllers or handlers are used to prepare a model using incoming information from the servlet request.
Interceptors are also components involved in the path of execution, intercepting the request, because they are given a chance to execute a piece of logic before and right after the handler does its work. Interceptors are a Good Thing (as is also proven by WebWork2) because they allow you to add additional logic to the path of execution, without affecting the handler itself. Interceptors resemble Servlet Filters a bit; those are also capable of intercepting the request to modify it or execute other behavior. Servlet Filters are part of the Servlet 2.3 specification. They differ from Spring HandlerInterceptors (as they are actually called) in that Filters are modeled on a more framework-independent level and allow for interaction with the request and the response at a lower level. Spring HandlerInterceptors are aware they're being executed in the context of the Spring Framework and allow for more framework-focused behavior, such as the modification of the ModelAndView or the inspection of an ApplicationContext. Just as Aspect Oriented Programming in general (covered in-depth in Chapter 4) greatly improves the degree of decoupling in your overall software design, HandlerInterceptors allow for adding behavior to the execution of a request without affecting the actual component handling the request.
Those of you switching from Struts to Spring MVC should carefully study the concept of Spring HandlerInterceptors. At the time of writing, Struts does not offer something similar — at least, not as part of its core. (The Struts Action Invocation Framework is an independent initiative offering interceptor behavior, located at http://struts.sourceforge.net/saif.) Interceptors are a powerful and useful concept when implementing web applications. They can significantly simplify implementing many common requirements, and improve maintainability thereafter.
After the path of execution has been determined, any interceptors found will be given a chance to intercept the incoming request. Each one of the interceptors can decide to stop the framework from further processing the request. This is useful in, for example, an interceptor for security purposes. If an interceptor chooses to stop the framework from further processing the request, the framework won't allow the handler (determined by the path of execution) to process the request.
If none of the interceptors halts flow down the execution chain, Spring will hand over control to the handler and allow it to process the request.
After a request has been preprocessed by the interceptors that were found (if any), Spring hands over control to the handler associated with the request. Such a handler should return a ModelAndView object. There are a couple of possible outcomes.
First of all, an exception might be thrown. In this case, Spring will inspect the WebApplicationContext for exception resolvers. Exception resolvers are components capable of inspecting an exception and determining an appropriate model-and-view relevant to the exception. If one of the resolvers results in a ModelAndView, this will be used to render a response to the client. Think of a warning to a user if a database connection couldn't be made or something similar. If the resolver(s) could not come up with an appropriate ModelAndView, the exception will be re-thrown, in which case the standard exception mapping mechanisms part of the servlet descriptor file (web.xml) might pick up on it.
There are two ways to deal with errors in a web application. When errors arise that you can't avoid or deal with using Spring's exception resolvers, we tend to use the infrastructure the web.xml deployment descriptor offers to take appropriate actions. To take appropriate actions when business exceptions occur or when a Spring proprietary exception occurs, usually we use the Spring exception resolver infrastructure.
If no exception is thrown, Spring will use the ModelAndView returned by the handler to render a response to the client.
Processing of the request should always result in a ModelAndView. If no ModelAndView is returned, Spring assumes that the handler itself has dealt with the request and no further action is taken (meaning Spring won’t start rendering a view).
All interceptors available in the path of execution are allowed to post process the request, just before Spring starts rendering a response and also right after rendering has finished. Finally, Spring informs you of the fact that request execution has finished. It does so using the event notification infrastructure of the ApplicationContext (which is further explained in Chapter 3). The event thrown here is the org.springframework.web.context.support.RequestHandledEvent.