SpringBoot learning notes Part08
1. WebMvcAutoConfiguration
SpringBoot starts and loads the xxxAutoConfiguration class (autoconfiguration class) by default. Webmvcoautoconfiguration is the autoconfiguration class of spring MVC function.
According to our previous study, open the spring automatic configuration class package in libs,
Find webmvcoautoconfiguration,
By observing its on-demand loading conditions, we can find that this configuration class is effective.
@Configuration( proxyBeanMethods = false ) @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class}) @ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) @AutoConfigureOrder(-2147483638) @AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class}) public class WebMvcAutoConfiguration {}
2. WebMvcAutoConfigurationAdapter
Next, we can observe what components are put in the container by this configuration class. Among them, a static internal class is webmvcoautoconfigurationadapter, which is also a configuration class.
@Configuration( proxyBeanMethods = false ) @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class}) @EnableConfigurationProperties({WebMvcProperties.class, WebProperties.class}) @Order(0) public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {}
When studying automatic configuration, you must pay attention to the annotation @ EnableConfigurationProperties, which is used to bind the data in the configuration file to the configuration file class. We can follow this clue to find out what it is configured with.
Open the source code of WebMvcProperties and ResourceProperties configuration file class, and we can find that the binding prefix of WebMvcProperties is spring The binding prefix of MVC and ResourceProperties is spring resources.
2.1 parametric constructor
Now look at the method body of the static internal class webmvcoautoconfigurationadapter. There is a constructor with parameters in the method body. In spring boot, if there is only one constructor with parameters, the values of all parameters of this constructor will be found from the IoC container.
public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) { this.resourceProperties = webProperties.getResources(); this.mvcProperties = mvcProperties; this.beanFactory = beanFactory; this.messageConvertersProvider = messageConvertersProvider; this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable(); this.dispatcherServletPath = dispatcherServletPath; this.servletRegistrations = servletRegistrations; this.mvcProperties.checkConfiguration(); }
By analyzing the above parameters, we can know their functions and functions:
- Resourceproperties: get and spring Resources bind to all the value objects
- WebMvcProperties mvcProperties: get and spring MVC binds all the value objects
- ListableBeanFactory: it is equivalent to finding the IoC container of Spring, that is, the bean factory of Spring
- HttpMessageConverters: find all HttpMessageConverters in the system (learn later)
- ResourceHandlerRegistrationCustomizer: locate the customizer for the resource processor
- DispatcherServletPath: the path that DispatcherServlet handles
- Servlet registrationbean: components that register servlets, filters, listeners, etc. for applications
Continuing to look at the method body, you can find that this configuration class adds many components to the container, and all load @ ConditionalOnMissingBean on demand. The following takes the source code of springmvc automatic injection view parser as an example, and there are many components, such as international message parser, formatter, file upload, etc.
@Bean @ConditionalOnMissingBean public InternalResourceViewResolver defaultViewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix(this.mvcProperties.getView().getPrefix()); resolver.setSuffix(this.mvcProperties.getView().getSuffix()); return resolver; }
2.2 default rules for resource processing
Next, we can find a method addResourceHandlers to add resource handlers. The default rules for all resources can be observed here.
public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); } else { //Rules for configuring webjars this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/"); //Rules for configuring static resource paths this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> { registration.addResourceLocations(this.resourceProperties.getStaticLocations()); if (this.servletContext != null) { ServletContextResource resource = new ServletContextResource(this.servletContext, "/"); registration.addResourceLocations(new Resource[]{resource}); } }); } }
In this resourceProperties. Isaddmappings() we can find that in spring Under the resources configuration file, there is a boolean attribute addMappings.
addMappings attribute: the default is true. If the configuration is false, the code segment of a series of components registered in else (observe the code to find that they are related configurations for static resource access) will not take effect.
spring: web: resources: add-mappings: false # Change it to false, and the final effect is to disable all static resources in the project, which can't be accessed anyway
There is an addResourceHandler method in addResourceHandlers. You can find that this method is actually used to register access rules.
private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, Consumer<ResourceHandlerRegistration> customizer) { if (!registry.hasMappingForPattern(pattern)) { ResourceHandlerRegistration registration = registry.addResourceHandler(new String[]{pattern}); customizer.accept(registration); //This method also has the function of cache control, which is used to cache these resources for a period of time. That is, after we visit it once, the browser will cache it for us, so we don't have to request this static file from the server every time. registration.setCachePeriod(this.getSeconds(this.resourceProperties.getCache().getPeriod())); registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl()); registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified()); this.customizeResourceHandlerRegistration(registration); } }
addResourceHandlers has been called twice, one for webjar rules and one for static resource access rules:
-
This explains why when learning about webjar before, webjar only needs / webjars / * * to access, because after registering the access rules, the static resource path of webjar is set to classpath:/META-INF/resources/webjars / by this method.
-
The static resource path also calls this method. Similarly. The final values obtained by the getStaticPathPattern and getStaticLocations methods are as follows:
private String staticPathPattern = "/**"; private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS; private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{ "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" };
This explains why there are four default static resource paths in our previous study.
When we modify the static resource path, we will follow the modified static resource path. In the request of "/ * * *", you will come to the set static resource path to get the resources, and there are also cache policies (all static resources have cache policies).
In addition, the addResourceHandler method also has the function of cache control, which is used to cache these resources for a period of time. That is, after we visit it once, the browser will cache it for us, so we don't have to request this static file from the server every time. We can also set the relevant information of cache policy in the configuration file:
spring: web: resources: cache: period: 10000
3. Processing rules of welcome page
Going back to the outermost WebMvcAutoConfiguration automatic configuration class at the beginning, we can find that there is also a configuration class EnableWebMvcConfiguration, which also puts many components in the IoC container. Among them is the welcome page we want to analyze.
Xx handlermapping is the core component of spring MVC, which is used for processor mapping. It stores which requests each Handler can handle. That is, after receiving the request, Handler mapping is responsible for finding out who handles the request and who handles the request. After finding it, it uses reflection to call the method that can handle the request.
Welcome pagehandlermapping is equivalent to the request mapping rule of "who can handle the welcome page". Let's start to analyze its source code.
@Bean public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) { WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern()); welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider)); welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations()); return welcomePageHandlerMapping; }
welcomePageHandlerMapping has many formal parameters, which spring will automatically get from the IoC container.
Then we enter the bottom constructor of new welcome pagehandlermapping(), and the source code is as follows.
final class WelcomePageHandlerMapping extends AbstractUrlHandlerMapping { WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders, ApplicationContext applicationContext, Resource welcomePage, String staticPathPattern) { if (welcomePage != null && "/**".equals(staticPathPattern)) { //To use the welcome page feature, you must be/** logger.info("Adding welcome page: " + welcomePage); this.setRootViewName("forward:index.html"); } else if (this.welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) { //If the static resource path is not / * *, submit a view named index to the Controller for processing logger.info("Adding welcome page template: index"); this.setRootViewName("index"); } } }
We finally found that "/". equals(staticPathPattern) is dead in the spring bottom layer, which also explains why the welcome page fails as soon as we modify the static resource path, because it is completely dead in the spring bottom source code.
Conclusion: due to the dead writing of spring bottom layer, when the static resource path is not modified, the welcome page is index html. However, in our actual development, we will modify the static resource path to distinguish the requests of the Controller. After we modify it, the welcome page function will submit a view with the path name of index to the Controller for processing. We can write this Controller with the name of index to realize the business and jump.
4. Processing rules of favicon
After understanding the underlying source code of spring MVC, we found that favicon has nothing to do with the code, because this is what browsers do. The browser will default to / favicon. Under the current project ICO and realize this function.