SpringBoot源码解析-自动配置SpringMVC

在上一小节SpringBoot源码解析-内嵌Tomcat,我们介绍了SpringBoot是如何启动一个内置tomcat的。

我们知道我们在SpringBoot项目里面是可以直接使用诸如@RequestMapping 这类的SpringMVC的注解,那么同学们会不会奇怪,这是为什么?

我明明没有配置SpringMVC为什么就可以使用呢?

其实仅仅引入starter是不够的,回忆一下,在一个普通的WEB项目中如何去使用SpringMVC,我们首先就是要在web.xml中配置如下配置

        <servlet>
            <description>spring mvc servlet</description>
            <servlet-name>springMvc</servlet-name>
            <servletclass>
                org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>springMvc</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>

但是在SpringBoot中,我们没有了web.xml文件,我们如何去配置一个Dispatcherservlet 呢?

其实Servlet3.0规范中规定,要添加一个Servlet,除了采用xml配置的方式,还有一种通过代码的方式,伪代码如下

servletContext.addServlet(name, this.servlet);

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

一、自动配置DispatcherServlet和DispatcherServletRegistry

springboot的自动配置基于SPI机制,实现自动配置的核心要点就是添加一个自动配置的类,SpringBoot MVC的自动配置自然也是相同原理。

所以,先找到springmvc对应的自动配置类。

  

 1.1 DispatcherServletAutoConfiguration自动配置类

1、首先注意到,@Configuration表明这是一个配置类,将会被spring给解析。

2、@ConditionalOnWebApplication意味着当是一个web项目,且是Servlet项目的时候才会被解析。

3、@ConditionalOnClass指明DispatcherServlet这个核心类必须存在才解析该类。

4、@AutoConfigureAfter指明在ServletWebServerFactoryAutoConfiguration这个类之后再解析,设定了一个顺序。

总的来说,这些注解表明了该自动配置类的会解析的前置条件需要满足。

其次,DispatcherServletAutoConfiguration类主要包含了两个内部类,分别是

1、DispatcherServletConfiguration

2、DispatcherServletRegistrationConfiguration

顾名思义,前者是配置DispatcherServlet,后者是配置DispatcherServlet的注册类。什么是注册类?

我们知道Servlet实例是要被添加(注册)到如tomcat这样的ServletContext里的,这样才能够提供请求服务。

所以,DispatcherServletRegistrationConfiguration将生成一个Bean,负责将DispatcherServlet给注册到ServletContext中。

1.2 配置DispatcherServletConfiguration

我们先看看DispatcherServletConfiguration这个配置类

@Conditional指明了一个前置条件判断,由DefaultDispatcherServletCondition实现。主要是判断了是否已经存在DispatcherServlet,如果没有才会触发解析。

@ConditionalOnClass指明了当ServletRegistration这个类存在的时候才会触发解析,生成的DispatcherServlet才能注册到ServletContext中。

@EnableConfigrationProperties将会从application.properties这样的配置文件中读取spring.http和spring.mvc前缀的属性生成配置对象HttpProperties和WebMvcProperties。

再看DispatcherServletConfiguration这个内部类的内部代码

这个两个方法我们比较熟悉了,就是生成了Bean。

dispatcherServlet方法将生成一个DispatcherServlet的Bean对象。比较简单,就是获取一个实例,然后添加一些属性设置。

multipartResolver方法主要是把你配置的MultipartResolver的Bean给重命名一下,防止你不是用multipartResolver这个名字作为Bean的名字。

 1.3 配置DispatcherServletRegistrationConfiguration

再看注册类的Bean配置

@Conditional有一个前置判断,DispatcherServletRegistrationCondition主要判断了该注册类的Bean是否存在。

@ConditionOnClass也判断了ServletRegistration是否存在

@EnableConfigurationProperties生成了WebMvcProperties的属性对象

@Import导入了DispatcherServletConfiguration,也就是我们上面的配置对象。

再看DispatcherServletRegistrationConfiguration的内部实现

内部只有一个方法,生成了DispatcherServletRegistrationBean。

核心逻辑就是实例化了一个Bean,设置了一些参数,如dispatcherServlet、loadOnStartup等。

1.3 总结

springboot mvc的自动配置类是DispatcherServletAutoConfigration,主要做了两件事:

1)配置DispatcherServlet

2)配置DispatcherServlet的注册Bean(DispatcherServletRegistrationBean)

二、注册DispatcherServlet到ServletContext

在上一小节的源码翻阅中,我们看到了DispatcherServlet和DispatcherServletRegistrationBean这两个Bean的自动配置。

DispatcherServlet我们很熟悉,DispatcherServletRegistrationBean负责将DispatcherServlet注册到ServletContext当中

2.1 DispatcherServletRegistrationBean的类图

既然该类的职责是负责注册DispatcherServlet,那么我们得知道什么时候触发注册操作。

为此,我们先看看DispatcherServletRegistrationBean这个类的类图

2.2 注册DispatcherServlet流程

2.2.1 ServletContextInitializer

我们看到,最上面是一个ServletContextInitializer接口。我们可以知道,实现该接口意味着是用来初始化ServletContext的。我们看看该接口

2.2.2 RegistrationBean

看看RegistrationBean是怎么实现onStartup方法的

 

调用了内部register方法,跟进它

 

 这是一个抽象方法

2.2.3 DynamicRegistrationBean

再看DynamicRegistrationBean是怎么实现register方法的

 

 跟进addRegistration方法

 

一样是一个抽象方法

 2.2.4 ServletRegistrationBean

再看ServletRegistrationBean是怎么实现addRegistration方法的

 我们看到,这里直接将DispatcherServlet给add到了servletContext当中。

2.3 SpringBoot启动流程中具体体现

getSelfInitializer().onStartup(servletContext);

这段代码其实就是去加载SpringMVC,那么他是如何做到的呢?

getSelfInitializer() 最终会去调用到ServletWebServerApplicationContext 的selfInitialize 方法,该方法代码如下

 

 

我们通过调试,知道getServletContextInitializerBeans() 返回的是一个ServletContextInitializer 集合,集合中有以下几个对象

 

然后依次去调用对象的onStartup 方法,那么对于上图标红的对象来说,就是会调用到DispatcherServletRegistrationBean 的onStartup 方法,

这个类并没有这个方法,所以最终会调用到父类RegistrationBean 的onStartup 方法,该方法代码如下

这边register(description, servletContext); 会调用到DynamicRegistrationBean 的register 方法,代码如下

 

 

addRegistration(description, servletContext) 又会调用到ServletRegistrationBean中的addRegistration 方法,代码如下

看到了关键的servletContext.addServlet 代码了,我们通过调试,即可知到this.servlet 就是dispatcherServlet

 三、总结

SpringBoot自动装配SpringMvc其实就是往ServletContext中加入了一个Dispatcherservlet 。

Servlet3.0规范中有这个说明,除了可以动态加Servlet,还可以动态加Listener,Filter

addServlet

addListener

addFilter

视频教程

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值