spring-mvc in Action

Agenda

  1. Context Initialization
  2. Request Routing
  3. Data Binding and Validation
  4. Exception Handling
  5. View Rendering

Overview

DispatcherServlet

	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}
  • Create its own internal web application context
  • Manages WebApplicationContext instance per servlet

  • Highly customizable supporting installation of different adapter classes

  • Central dispatcher for HTTP request handlers/controllers

  • Publishes events on request processing 

Initialization of Root WebContext

package javax.servlet;

import java.util.EventListener;

public interface ServletContextListener extends EventListener {

    public void contextInitialized(ServletContextEvent sce);

    public void contextDestroyed(ServletContextEvent sce);
}

Notified of context initialization before any filters or servlets in the web application are initialized

  • contextInitialized() in the order of declaration
  • contextDestroyed() in reverse

Initialization of Root WebContext (Cont...)

<listener>
    <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

WEB-INF/web.xml

Initialization of Root WebContext (Cont...)

org.springframework.web.context.ContextLoaderListener
	public void contextInitialized(ServletContextEvent event) {
		this.contextLoader = createContextLoader();
		if (this.contextLoader == null) {
			this.contextLoader = this;
		}
		this.contextLoader.initWebApplicationContext(event.getServletContext());

               //org.springframework.web.context.ContextLoader#initWebApplicationContext
	}
  1. contextClass

  2. contextConfigLocation

Configuration:

Context Loader Performs the actual initialization work for the root application context

Initialization of WebContext (Cont..)

    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.XmlWebApplicationContext</param-value>
    </context-param>

i. xml based configuration

    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>


@EnableWebMvc

ii. annotation based configuration

contextClass configuration

Initialization of WebContext (Cont..)

contextConfigLocation configuration

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext1.xml, WEB-INF/applicationContext2.xml</param-value>
    </context-param>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/*Context.xml,WEB-INF/spring*.xml</param-value>
    </context-param>

i.

ii.

iii.

iv.

/** Default config location for the root context */
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

Loading beans From configLocation

Loading the xml document

- org.springframework.beans.factory.xml.DefaultDocumentLoader

Default: javax.xml.parsers.DocumentBuilder

java -Djavax.xml.parsers.DocumentBuilderFactory=oracle.xml.jaxp.JXDocumentBuilderFactory

BeanDefinitionRegistry

Interface for registries that hold bean definitions

 

org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition

    private boolean allowBeanDefinitionOverriding = true;

HandlerMapping

HandlerInterceptor

HandlerAdapter

Responsibility

  1. Mapping between requests and handler objects
public interface Ordered {

	int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;

	int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

	int getOrder();

}

HandlerMapping

//DispatcherServlet.properties

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

BeanNameUrlHandlerMapping

 

beans with names that start with a slash ("/")

 

    <bean id="/oldHome" class="net.therap.controller.OldProjectController"></bean>
    <bean id="/oldHome.html" class="net.therap.controller.OldProjectController"></bean>
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/project.htm">oldProjectController</prop>
                <prop key="/oldProject*">oldProjectController</prop>
                <prop key="/pilotProject">oldProjectController</prop>
            </props>
        </property>
    </bean>

    <bean name="oldProjectController" class="net.therap.controller.OldProjectController"/>

SimpleUrlHandlerMapping

HandlerMapping

Request Resolving

org.springframework.web.servlet.DispatcherServlet#getHandler(javax.servlet.http.HttpServletRequest)	

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		for (HandlerMapping hm : this.handlerMappings) {
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}

HandlerMapping

For annotated request mapping

1. DefaultAnnotationHandlerMapping (@deprecated in spring mvc 3.2) in favor of
2. RequestMappingHandlerMapping (From spring mvc 3.1)

What's new

  • HandlerMethodReturnValueHandler customization

        - preHandle()

after: HandlerMapping determined handler object
before: HandlerAdapter invokes the handler

 

        - postHandle()

after: HandlerAdapter actually invoked the handler
before: DispatcherServlet renders the view

 

        - afterCompletion()

after: rendering the view

invoked in reverse order, so the first interceptor will be the last to be invoked.

 

HandlerInterceptor

Registering HandlerInterceptor

    <mvc:interceptors>
        <bean id="webContentInterceptor" class="org.springframework.web.servlet.mvc.WebContentInterceptor">
            <property name="cacheSeconds" value="0"/>
            <property name="useExpiresHeader" value="true"/>
            <property name="useCacheControlHeader" value="true"/>
            <property name="useCacheControlNoStore" value="true"/>
        </bean>
    </mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/resources/**"/>
            <bean class="net.therap.interceptor.ProfilerInterceptor"/>
        </mvc:interceptor>

ProfilerInterceptor extends HandlerInterceptorAdapter

Custom HandlerInterceptor

Request Resolving

public interface HandlerMapping {
        ...

	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
public class HandlerExecutionChain {

	private final Object handler;

	private HandlerInterceptor[] interceptors;

	private List<HandlerInterceptor> interceptorList;

}
org.springframework.web.servlet.DispatcherServlet#doDispatch

#1 Determining HanlderMapping for current request

  • Check Ambiguous handler methods mapped for HTTP path
  • Return a HandlerExecutionChain adding all path mathed interceptors

Request Resolving

public interface HandlerAdapter {

	boolean supports(Object handler);
 
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

	long getLastModified(HttpServletRequest request, Object handler);
}

#2 Determining HanlderAdapter

Request Resolving

1. mappedHandler.applyPreHandle(processedRequest, response) // HandlerExecutionChain

   Invoke preHandle() of all registered interceptors
3. Determines viewName, if not provided - viewNameTranslator.getViewName(request)
2. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
4. Invoke postHandle() of all registered interceptors in reverse order
5. Render view
1. Map<Class<?>, ServletHandlerMethodResolver> methodResolverCache 
2. AnnotationUtils.findAnnotation(method, RequestMapping.class)

First Step

Second Step

#2 Determining HanlderAdapter

Thank you

Spring In Action

By MUHAMMAD SHAKHAWAT HOSSAIN SAFAT