Close

Spring MVC - Understanding ViewResolver

[Last Updated: Aug 12, 2017]

In this tutorial, we will understand what ViewResolver is. We will also analyze the way its instances are configured/registered and how they are used by DispatcherServlet.

The ViewResolver interface

package org.springframework.web.servlet;
 .............
public interface ViewResolver {
    View resolveViewName(String viewName, Locale locale) throws Exception;
}

As seen above, the method resolveViewName() resolves views by name. It returns an instance of View interface.

The View interface

This is the 'V' part of Spring MVC. Let's see its snippet:

package org.springframework.web.servlet;
 ....
public interface View {
    String getContentType();
    void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
                                                                                  throws Exception;
}

The method getContentType() returns the media type which this View supports.

The method render() is responsible to render the view.

The ViewResolver registration

If we are using @EnableWebMvc, then WebMvcConfigurationSupport will be used for ViewResolver configuration.

Let's see the snippet of WebMvcConfigurationSupport, where ViewResolver is registered as bean (Spring version 4.3.10.RELEASE).

public class WebMvcConfigurationSupport implements .... {
    ......
    @Bean
    public ViewResolver mvcViewResolver() {
        ViewResolverRegistry registry = new ViewResolverRegistry();
        registry.setContentNegotiationManager(mvcContentNegotiationManager());
        registry.setApplicationContext(this.applicationContext);
        configureViewResolvers(registry); 1

        if (registry.getViewResolvers().isEmpty()) {    2
            String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this.applicationContext, ViewResolver.class, true, false);
            if (names.length == 1) { 3
                    registry.getViewResolvers().add(new InternalResourceViewResolver()); 4
            }
        }

        ViewResolverComposite composite = new ViewResolverComposite();
        composite.setOrder(registry.getOrder());
        composite.setViewResolvers(registry.getViewResolvers());
        composite.setApplicationContext(this.applicationContext);
        composite.setServletContext(this.servletContext);
        return composite; 5
    }
    ....
}

1 This is where our overridden configureViewResolvers() method of WebMvcConfigurerAdapter will be invoked.

2 This condition will be true if we did not register any ViewResolver via WebMvcConfigurerAdapter.

3 This condition will be true if no ViewResolver has been registered as bean by our application (by using @Bean) and hence there's exactly one ViewResolver registered (which is by this @Bean method, see here as well).

4 An instance of InternalResourceViewResolver with no other configuration is registered. InternalResourceViewResolver#resolveViewName() returns InternalResourceView (which supports Servlets and JSPs) and subclasses such as JstlView. By default its 'suffix' and 'prefix' are set as empty string, that means our application has to use full path for views.

5 An instance of ViewResolverComposite is finally returned and hence registered as bean named 'mvcViewResolver'. ViewResolverComposite does not resolves the view itself but delegates the request to its list of ViewResolvers.

To summarize above configuration in simple words: if we haven't registered any ViewResolver by overriding WebMvcConfigurerAdapter or by registering directly via @Bean then a default instance of InternalResourceViewResolver will be used, otherwise our registered ones will be used.

Also, the ViewResolver(s) registered via WebMvcConfigurerAdapter are added to above ViewResolverComposite's list and the ViewResolver(s) registered via @Bean will be used by DispatchServlet directly (next section).

DispatcherServlet and ViewResolvers

In this section, we will discuss how DispatcherServlet uses ViewResolvers.

  • The flag detectAllViewResolvers

    DispatcherServlet uses the flag detectAllViewResolvers which affects the way it detects the ViewResolvers. By default it is set to true, that means all ViewResolvers registered by our application and the one registered by WebMvcConfigurationSupport will be used. DispatcherServlet uses BeanFactoryUtils.beansOfTypeIncludingAncestorsIf() method to find the resolvers. This logic is implemented in DispatcherServlet#initViewResolvers()

  • If detectAllViewResolvers=false

    If detectAllViewResolvers flag is set to false (which can be done similar to this example) then DispatcherServlet expects only one ViewResolver be registered with name 'viewResolver' (DispatcherServlet#VIEW_RESOLVER_BEAN_NAME); and only this ViewResolver will be used. We will probably use this option, if we want to use only one ViewResolver and ignore the rest of the registered resolvers.

  • The ViewResolvers order

    DispatcherServlet keeps the detected ViewResolvers in an instance list. This list is sorted by AnnotationAwareOrderComparator, which uses Ordered interface or @Order or @Priority. If a ViewResolver does not support any of these then it is kept in Ordered.LOWEST_PRECEDENCE position.

  • How DispatcherServlet uses ViewResolvers?

    During handling an HTTP request, the DispatcherServlet uses its ViewResolver list at the point when our controller method has returned a ModelAndView instance already and view is about to be rendered (this logic starts from DispatcherServlet#render()). The view name returned by ModelAndView is used to resolve the View. The DispatcherServlet's ViewResolver list is iterated and ViewResolver#resolveViewName() is called one by one. The First non-null View, returned from this call, is used and the rest are skipped. The specific View implementation found is used for rendering the view by calling its View#render method. The rendering depends how a specific View is implemented, for example InternalResourceView uses RequestDispatcher#forward to forward the request to the target JSP page, which is then rendered by the JSP engine.

The ViewResolver Implementations

Check out the implementations here. In upcoming tutorials, we will be exploring some of these implementations with examples.

See Also