Close

Spring MVC - Understanding ViewResolver

[Last Updated: Sep 30, 2026]

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

The ViewResolver interface

Definition of ViewResolver

Version: 7.0.6
 package org.springframework.web.servlet;
 public interface ViewResolver {
     View resolveViewName(String viewName, 1
                          Locale locale)
                          throws Exception;
 }
1Resolve the given view by name.

As seen above, the method resolveViewName() resolves a view by name. It returns an instance of the View interface, or null if no view with the given name can be found. That null is what allows DispatcherServlet to move on and ask the next ViewResolver in its list.

The View interface

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

Definition of View

Version: 7.0.6
 package org.springframework.web.servlet;
 public interface View {
     default String getContentType(); 1
     void render(@Nullable Map<String, ?> model, 2
                 HttpServletRequest request,
                 HttpServletResponse response)
                 throws Exception;
 }
1Return the content type of the view, if predetermined.
2Render the view given the specified model.

The ViewResolver registration

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

Let's see the snippet of WebMvcConfigurationSupport, where a ViewResolver is registered as a bean (Spring version 4.3.10.RELEASE). The overall logic is still the same in current Spring versions, although the method signature and some null checks have changed in later releases.

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

        if (registry.getViewResolvers().isEmpty() && 
                                  this.applicationContext != null)) {    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());
        if (this.applicationContext != null) {
          composite.setApplicationContext(this.applicationContext);
        }
        if (this.servletContext != null) { 
        composite.setServletContext(this.servletContext);
        }
        return composite; 5
    }
    ....
}

1 This is where the overridden configureViewResolvers() method of our WebMvcConfigurer implementation will be invoked.

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

3 This condition will be true if our application has not registered any ViewResolver as a bean (by using @Bean). In that case, there's exactly one ViewResolver bean, which is the one created by this @Bean method (see here as well).

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

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

To summarize the above configuration in simple words: if we haven't registered any ViewResolver by overriding WebMvcConfigurer#configureViewResolvers() or by registering one 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 WebMvcConfigurer are added to the above ViewResolverComposite's list, and the ViewResolver(s) registered via @Bean will be used by DispatcherServlet 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, which means all ViewResolvers registered by our application and the one registered by WebMvcConfigurationSupport will be used. DispatcherServlet uses the BeanFactoryUtils.beansOfTypeIncludingAncestors() method to find the resolvers. This logic is implemented in DispatcherServlet#initViewResolvers().

  • If detectAllViewResolvers=false

    If the detectAllViewResolvers flag is set to false (which can be done similarly to this example), then DispatcherServlet expects exactly one ViewResolver to be registered with the 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 the Ordered interface, @Order or @Priority. If a ViewResolver does not support any of these, then it is kept in the Ordered.LOWEST_PRECEDENCE position.

  • How does DispatcherServlet use ViewResolvers?

    While handling an HTTP request, DispatcherServlet uses its ViewResolver list at the point when our controller method has already returned and a view is about to be rendered. If the controller returns a view name (e.g. a String), it is wrapped in a ModelAndView; if it returns a ModelAndView, that is used directly. (Methods annotated with @ResponseBody, or returning ResponseEntity, skip view resolution completely.) This logic starts from DispatcherServlet#render(). The view name of the 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 on 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

Join