spring mvc architecture - MAlghafary/spring-mvc GitHub Wiki

Request Life Cycle

  • DispatcherServlet : the fornt-controller in spring MVC
  • DS will forward to one or more handler-mappings, to get back the controller
  • DS sends the request to the controller
  • Request processed by the controller, in traditional web apps, the controller will include a logical view name in the result it produces
  • DS talks to the view-resolver(one or more) to resolve the logical view name to an actual View(in case of traditional web apps only, in REST Apis, the return value from the handler method will be converted to an HttpResponse)
  • DS forwards the request to the view including the model,view will use the model to render and send to client via the response object.

Dispatcher Servlet Configuration (Note:not the same thing in sprint boot )

  • Traditional approach (through web.xml),still supported but not very popular these days.
  • With Servlets 3.0,you can configure servlets using Java, here how it works :

-- The Servlet container will search for any class in the classpath that implements SPI : ServletContainerInitializer https://docs.oracle.com/javaee/7/api/javax/servlet/ServletContainerInitializer.html

-- Implementations of this interface may be annotated with HandlesTypes, in order to receive (at their onStartup(java.util.Set<java.lang.Class<?>>, javax.servlet.ServletContext) method) the Set of application classes that implement, extend, or have been annotated with the class types specified by the annotation.

-- Spring provides an implementation for this interface : SpringServletContainerInitializer, this class will receive all classes implementing WebApplicationInitializer and will call the onStartup passing the ServletContext, then the servlet context can be used to do the configuration (Add Servlets/Filters/.. )

-- One of the options to configure the DispatcherServlet is to create a class that implements the
WebApplicationInitializer interface : ` public class MyWebInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {

    var ctx = new AnnotationConfigWebApplicationContext();
    ctx.register(WebConfig.class);
    ctx.setServletContext(servletContext);

    var servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
    servlet.setLoadOnStartup(1);
    servlet.addMapping("/");
}

} `

-- Spring 3.2 introduced a convenient base implementation of WebApplicationInitializer called AbstractAnnotationConfigDispatcherServletInitializer, another option is to create a class extending this class: 1- GetServletsMapping : the path to where ds servlet will be mapped 2- getRootConfigClasses >> see below : can return null as in the spring documentation 3- getServletConfigClasses >> see below

A TALE OF TWO APPLICATION CONTEXTS When DispatcherServlet starts up, it creates a Spring application context and starts loading it with beans declared in the configuration files or classes that it’s given. With the getServletConfigClasses() method in listing 5.1, you’ve asked that Dispatcher- Servlet load its application context with beans defined in the WebConfig configuration class (using Java configuration). But in Spring web applications, there’s often another application context. This other application context is created by ContextLoaderListener. Whereas DispatcherServlet is expected to load beans containing web components such as controllers, view resolvers, and handler mappings, ContextLoaderListener is expected to load the other beans in your application. These beans are typically the middle-tier and data-tier components that drive the back end of the application.

Under the covers, AbstractAnnotationConfigDispatcherServletInitializer creates both a DispatcherServlet and a ContextLoaderListener. The @Configuration classes returned from getServletConfigClasses() will define beans for Dispatcher- Servlet’s application context. Meanwhile, the @Configuration class’s returned get- RootConfigClasses() will be used to configure the application context created by ContextLoaderListener. In this case, your root configuration is defined in RootConfig, whereas Dispatcher- Servlet’s configuration is declared in WebConfig. You’ll see what those two configuration classes look like in a moment.

Good details here : https://stackoverflow.com/questions/35258758/getservletconfigclasses-vs-getrootconfigclasses-when-extending-abstractannot/35441381

configuring the dispatcher servlet with java config requires Servlet 3.0, such as Apache Tomcat 7
Spring MVC Configuration : The very simplest Spring MVC configuration you can create is a class annotated with @EnableWebMvc, example : ` package spittr.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration @EnableWebMvc public class WebConfig { } `

This will work, and it will enable Spring MVC. But it leaves a lot to be desired:  No view resolver is configured. As such, Spring will default to using Bean- NameViewResolver, a view resolver that resolves views by looking for beans whose ID matches the view name and whose class implements the View interface.  Component-scanning isn’t enabled. Consequently, the only way Spring will find any controllers is if you declare them explicitly in the configuration.  As it is, DispatcherServlet is mapped as the default servlet for the application and will handle all requests, including requests for static resources, such as images and stylesheets (which is probably not what you want in most cases).

@Configuration @EnableWebMvc @ComponentScan("spitter.web") public class WebConfig extends WebMvcConfigurerAdapter { >> in spring 5+ you can replace this with implements WebMvcConfigurer ( using java 8 default methods )

@Bean public ViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true); return resolver; } @Override public void configureDefaultServletHandling( DefaultServletHandlerConfigurer configurer) { configurer.enable(); } }

How this is works again : -> The configuration class ( WebConfig ) is created ( passed to AnnotationConfigWebApplicationContext ) -> AnnotationConfigWebApplicationContext will use the WebConfig to configure the beans ( @Bean + Component Scanning ) this will create an ApplicaionContext with the beans (like viewResolvers,handler mappings .. ) -> The AnnotationConfigWebApplicationContext is passed to the DS in the constructor, when the DS needs a bean to complete a request, it will get it from the ApplicaionContext -> The methods of the WebMvcConfigurer are callback methods and they will called while configuring the different aspects of spring mvc (handlers,mappings,messageConvertoers).. could they just made regular beans ? maybe not all the time.. in a case where you want to change a small thing, not to provide a totally diffent bean, maybe some of the configuration is not directly reporestned as beans... this is confusing nevertheless.

Cases where you need to implement the WebMvcConfigurer : 1- ViewControllerRegistry ?? 2- Static files 3- CustomMessageConverters .. other things

RootConfig can be null/empty class Follow here : https://www.javacodegeeks.com/2018/04/spring-mvc-tutorial-2.html : Chapter 5 ( Spring in action,4th edition )