springboot源码理解十二、springMVC功能

时间:2022-09-26 13:18:32


springboot版本:2.2.9.RELEASE。

回忆一下,我们在普通的web项目中是如何使用springMVC的,
首先需要在web.xml中配置DispatcherServlet,

<servlet>
	<servlet-name>springMVC</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>springMVC</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

但是在springboot中没有web.xml文件,那我们如何去配置一个DispatcherServlet?

servlet实例是需要添加/注册到像tomcat这样的servletContext中,才能对外提供服务的。
在Servlet3.0规范中,提供了另外一种添加servlet的方式,
类似这样子:

servletContext.addServlet(name, this.servlet);

在Servlet3.0规范中,
容器启动时会自动扫描所有已添加的jar包下META-INF\services\javax.servlet.ServletContainerInitializer中指定的类的全路径,
实例化该类,然后回调META-INF\services\javax.servlet.ServletContainerInitializer中指定的ServletContainerInitializer的实现类的onStartUp方法。
springboot源码理解十二、springMVC功能
springboot源码理解十二、springMVC功能
如果我们能动态地往web容器中添加一个我们构造好的DispatcherServlet对象,就能实现springMVC配置了。

分两步:
1、DispatcherServlet加载到Spring IoC容器;
2、DispatcherServlet注册到servlet容器tomcat

DispatcherServlet加载到Spring IoC容器

springMVC自动配置类

打开spring-boot-2.2.9.RELEASE\spring-boot-project\spring-boot-autoconfigure\src\main\resources\META-INF\spring.factories,
DispatcherServletAutoConfiguration就是DispatcherServlet的自动配置类。
springboot源码理解十二、springMVC功能
DispatcherServletAutoConfiguration
springboot源码理解十二、springMVC功能
看下它的内部类,

DispatcherServletAutoConfiguration.DispatcherServletConfiguration

springboot源码理解十二、springMVC功能
spring启动时会将DispatcherServlet加载到IoC容器中去。

DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration

springboot源码理解十二、springMVC功能
spring启动时会将DispatcherServletRegistrationBean加载到IoC容器中去,
DispatcherServletRegistrationBean是DispatcherServlet它的一个注册类,
负责将DispatcherServlet注册到ServletContext中。

DispatcherServlet注册到servlet容器tomcat

ServletContextInitializer

我们先来看下DispatcherServletRegistrationBean的类关系图,
springboot源码理解十二、springMVC功能
发现它是ServletContextInitializer的一个实现类,

ServletContextInitializer和我们上边提到过的ServletContainerInitializer的作用类似,
我们看下ServletContainerInitializer,
发现只有一个onStartup方法。
springboot源码理解十二、springMVC功能
我们根据DispatcherServletRegistrationBean的类关系图查看它的实现方法,

org.springframework.boot.web.servlet.ServletContextInitializer#onStartup

org.springframework.boot.web.servlet.RegistrationBean#onStartup
springboot源码理解十二、springMVC功能

org.springframework.boot.web.servlet.DynamicRegistrationBean#register
springboot源码理解十二、springMVC功能

org.springframework.boot.web.servlet.ServletRegistrationBean#addRegistration

终于到了这一步,就是在这儿把DispatcherServlet注册到servlet容器的。
springboot源码理解十二、springMVC功能
那ServletContainerInitializer.onStartup是在什么时候被调用的?

我们还得回到AbstractApplicationContext#refresh这一步。

onRefresh

SpringBootMytestApplication#main

SpringApplication#run(java.lang.Class<?>, java.lang.String...) → SpringApplication#run(java.lang.Class<?>[], java.lang.String[])

SpringApplication#run(java.lang.String…)

SpringApplication#refreshContext

SpringApplication#refresh

AbstractApplicationContext#refresh

ServletWebServerApplicationContext#onRefresh

ServletWebServerApplicationContext#createWebServer
springboot源码理解十二、springMVC功能

org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#getSelfInitializer

org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#selfInitialize
springboot源码理解十二、springMVC功能
这一步就是获取ServletContextInitializer,执行onStartup方法,
至此,DispatcherServlet就注册到servletContext了。