springboot源码理解十二、springMVC功能
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-INFservicesjavax.servlet.ServletContainerInitializer中指定的类的全路径, 实例化该类,然后回调META-INFservicesjavax.servlet.ServletContainerInitializer中指定的ServletContainerInitializer的实现类的onStartUp方法。 如果我们能动态地往web容器中添加一个我们构造好的DispatcherServlet对象,就能实现springMVC配置了。
分两步: 1、DispatcherServlet加载到Spring IoC容器; 2、DispatcherServlet注册到servlet容器tomcat
DispatcherServlet加载到Spring IoC容器
springMVC自动配置类
打开spring-boot-2.2.9.RELEASEspring-boot-projectspring-boot-autoconfiguresrcmain esourcesMETA-INFspring.factories, DispatcherServletAutoConfiguration就是DispatcherServlet的自动配置类。 DispatcherServletAutoConfiguration 看下它的内部类,
DispatcherServletAutoConfiguration.DispatcherServletConfiguration
spring启动时会将DispatcherServlet加载到IoC容器中去。
DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration
spring启动时会将DispatcherServletRegistrationBean加载到IoC容器中去, DispatcherServletRegistrationBean是DispatcherServlet它的一个注册类, 负责将DispatcherServlet注册到ServletContext中。
DispatcherServlet注册到servlet容器tomcat
ServletContextInitializer
我们先来看下DispatcherServletRegistrationBean的类关系图, 发现它是ServletContextInitializer的一个实现类,
ServletContextInitializer和我们上边提到过的ServletContainerInitializer的作用类似, 我们看下ServletContainerInitializer, 发现只有一个onStartup方法。 我们根据DispatcherServletRegistrationBean的类关系图查看它的实现方法,
org.springframework.boot.web.servlet.ServletContextInitializer#onStartup → org.springframework.boot.web.servlet.RegistrationBean#onStartup → org.springframework.boot.web.servlet.DynamicRegistrationBean#register → org.springframework.boot.web.servlet.ServletRegistrationBean#addRegistration
终于到了这一步,就是在这儿把DispatcherServlet注册到servlet容器的。 那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 → org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#getSelfInitializer → org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#selfInitialize 这一步就是获取ServletContextInitializer,执行onStartup方法, 至此,DispatcherServlet就注册到servletContext了。
