A study note based on Spring MVC Documentation. Spring MVC is built on the Servlet API. The current version is 5.3.0.

1 DispatcherServlet

The servlet, DispatcherServlet, provides a shared algorithm for request processing, while actual work is performed by configurable delegate components. Both the DispatcherServlet and its delegate components need to be declared and mapped. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class MyWebApplicationInitializer : WebApplicationInitializer {

    override fun onStartup(servletContext: ServletContext) {

        // Load Spring web application configuration
        val context = AnnotationConfigWebApplicationContext()
        context.register(AppConfig::class.java)

        // Create and register the DispatcherServlet
        val servlet = DispatcherServlet(context)
        val registration = servletContext.addServlet("app", servlet)
        registration.setLoadOnStartup(1)
        registration.addMapping("/app/*")
    }
}

2 Special Bean Types

The DispatcherServlet checks the WebApplicationContext for special beans and delegates to special beans to process requests and render the appropriate responses.

  • HandlerMapping: Map a request to a handler along with a list of interceptors for pre- and post-processing. The mapping is based on some criteria. Two main implementations are
    • RequestMappingHandlerMapping: supports @RequestMapping.
    • SimpleUrlHandlerMapping: maitains explicit registrations of URI path patterns to handlers.
  • HandlerAdapter: helps DispatcherServlet to invoke a handler mapped to a request. It hides the handler invokation details.
  • HandlerExceptionsResolver: strategy to resolve exceptions. Exceptions can be handled by mapping class names to error view names, mapping exception to HTTP status codes etc.
  • ViewResolver: Resolve logic string-vased view names returned from a handler to an actual View.
  • LocalResolver: resolve the Locale.
  • ThemeResolver: resolve themes.
  • MultipartResolver: parse a multi-part request such as file upload.
  • FlashMapManager: store and retrieve the input and output FlashMap that can be used to pass attributes from one request to another, usually across redirect.

3 Processing

The WebApplicationContext is searched for and bound in the request as an attribute that the controller and other elements in the process can use.

An appropriate handler is searched for. If a handler is found, the execution chain associated with the handler (preprocessors, postprocessors, and controllers) is run to prepare a model for rendering. Alternatively, for annotated controllers, the response can be rendered (within the HandlerAdapter) instead of returning a view.

If a model is returned, the view is rendered. If no model is returned (maybe due to a preprocessor or postprocessor intercepting the request, perhaps for security reasons), no view is rendered, because the request could already have been fulfilled.

All HandlerMapping implementations support handler interceptors that are useful when you want to apply specific functionality to certain requests — for example, checking for a principal. Interceptors must implement HandlerInterceptor that provide three methods: preHandle(), postHandle() and afterCompletion().

4 Annotated Controllers

Spring MVC provides an annotation-based programming model where @Controller and @RestController components use annotations to express request mappings, request input, exception handling, and more.

You can use the @RequestMapping, or the more specific @GetMapping and @PostMapping annotations to map requests to controllers methods. It has various attributes to match by URL, HTTP method, request parameters, headers, and media types. You can use it at the class level to express shared mappings or at the method level to narrow down to a specific endpoint mapping.

The @RequestMapping handler methods have a flexible signature and can choose from a range of supported controller method arguments and return values. Arugments include @RequestHeader, @RequestBody, @ModelAttribute, @RequestParam, @CookieValue etc. Return values could be @ResponseBody, String, View etc.

5 Functional Endpoints

Spring Web MVC includes WebMvc.fn, a lightweight functional programming model in which functions are used to route and handle requests and contracts are designed for immutability. It runs on the same DispatcherServlet.

In WebMvc.fn, Incoming requests are routed to a handler function with a RouterFunction: a function that takes ServerRequest and returns an optional HandlerFunction. HandlerFunction is a function that takes ServerRequest and returns a ServerResponse. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import org.springframework.web.servlet.function.router

val repository: PersonRepository = ...
val handler = PersonHandler(repository)

val route = router {
    accept(APPLICATION_JSON).nest {
        GET("/person/{id}", handler::getPerson)
        GET("/person", handler::listPeople)
    }
    POST("/person", handler::createPerson)
}

ServerRequest provides access to the HTTP method, URI, headers, body and query parameters. ServerResponse provides access to the HTTP response and, since it is immutable, you can use a build method to create it. You can use the builder to set the response status, to add response headers, or to provide a body.

You can filter handler functions by using the before or after methods on the routing function builder.