回顾SpringMVC发送请求的配置

在SpringBoot 项目里面是可以直接使用诸如 @RequestMapping 这类的SpringMVC的注解,那么这是为什么?我明明没有配置SpringMVC为什么就可以使用呢?
其实仅仅引入starter是不够的,回忆一下,在一个普通的WEB项目中如何去使用SpringMVC首先就是要在web.xml中配置如下配置 DispatcherServlet 这个Servlet。

  1. <servlet>
  2. <description>spring mvc servlet</description>
  3. <servlet-name>springMvc</servlet-name>
  4. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  5. <load-on-startup>1</load-on-startup>
  6. </servlet>
  7. <servlet-mapping>
  8. <servlet-name>springMvc</servlet-name>
  9. <url-pattern>*.do</url-pattern>
  10. </servlet-mapping>


但是在SpringBoot中,并没有web.xml文件,又是如何去配置一个 Dispatcherservlet 呢? 其实Servlet3.0规范中规定,要添加一个Servlet,除了采用xml配置的方式,还有一种通过代码的 方式,伪代码如下

  1. servletContext.addServlet(name, this.servlet);

也就是说,如果要能动态往web容器中添加一个构造好的 DispatcherServlet 对象, 是不是就实现自动装配SpringMVC了

可以先看看Servlet的结构图

image.png

SpringBoot中能实现请求接收发送必须具备条件

1、通过自动配置从文件获取到 DispatcherServlet 工厂路径并进行实例化存放到IOC容器中
2、必须将 DispatcherServlet 存放到ServletContext容器中。(因为Servlet实例必须要注册到Tomcat的ServletContext中,才能够进行请求服务)
image.png
image.png
会去加载这个类,并将其类进行实例化
因为在Servlet启动的过程中,会去回调SpringServletContainerInitializer中的onStratup方法
在onStratup方法中,一步步剖析就能发现如何进行将实例注册到ServletContext的。添加后,就能进行正常的接收请求,并进行响应返回等。
image.png

源码剖析的追踪问题

第一点SpringMVC是如何通过自动装配生成实例存到IOC容器
第二点DispatcherServlet 是如何将其注册到ServletContext中的

问题一

1、从main方法的注解入手

image.png

2、进入实现自动装配的注解

image.png

3、进入自动导入的类

通过Spring底层注解@Import,给容器注入一个组件
image.png

4、经过debug发现SpringMVC的自动配置类

image.png

5、全局搜索spring.factories

image.png
image.png

6、查看DispatcherServletAutoConfiguration

image.png

6.1、看第一个内部类

image.png

6.2、看第二个内部类

image.png
第一个问题就是干这个事
image.png
image.png

问题二

在上一小节的源码翻阅中,已经看到了DispatcherServletDispatcherServletRegistrationBean 这两个Bean的自动配置。DispatcherServlet我们很熟悉,DispatcherServletRegistrationBean负 责将DispatcherServlet注册到ServletContext当中 。

DispatcherServletRegistrationBean的类图

然该类的职责是负责注册DispatcherServlet,那么得知道什么时候触发注册操作。为此, 我们先看看DispatcherServletRegistrationBean这个类的类图
DispatcherServletRegistrationBean.png

看注册DispatcherServlet流程

1、从顶层接口 ServletContextInitializer 看

最上面是一个ServletContextInitializer接口。实现该接口意味着是用 来初始化ServletContext的。我们看看该接口。通过这个方法就可以省去xml
image.png

2、安装类图找子类RegistrationBean

image.png

3、按照类图查找

image.png

4、继续进入

再看DynamicRegistrationBean是怎么实现register方法的 ,进入 跟进addRegistration方法
image.png

5、根据类图往下找

image.png

6、将DispatcherServlet添加到servletContext中

这里直接将DispatcherServlet给add到了servletContext当中。
image.png

接下来分析如何去调用得到这个addRegistration方法的呢?

有两种分析方式:

只有知道什么时候调用的,才能知道什么时候去存吧!
回到主函数的run方法,一路进去,refreshContext-》refresh-》
然后跳到Spring容器的onRefresh方法,继续进入ServletWebServerApplicationContext#createWebServer

从createWebServer开始分析,先从正面分析

1、进入getSelfInitializer

因为这里能返回是服务器,那么服务器里面肯定是有ServletContext的
image.png

2、进入getSelfInitializer方法的selfInitialize方法image.png

3、进入接口的onStartup方法

image.png

4、调用实现类

image.png

5、继续调用到子类

image.png

6、将其放入到容器中

image.png

总结

SpringBoot自动装配SpringMvc其实就是往ServletContext中加入了一个 Dispatcherservlet 。
Servlet3.0规范中有这个说明,除了可以动态加Servlet,
还可以动态加Listener,Filter addServlet addListener addFilter

还要一个方法,就是直接打断点这里,然后通过debug及调用栈进行反推

关键的一步是在从Spring源码onRefresh方法到createWebServer方法中,这步骤是关键

有时间在将时序图画出来。