SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

科技资讯 投稿 23500 0 评论

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

零丶引入

我在初学spring的时候,很懵逼,因为整个项目中不存在main方法,让我有点摸不着头脑。那时候我知道有个东西叫tomcat是它监听了端口,解析了协议调到了我的servlet。

一丶原生tomcat启动流程

在springboot内嵌tomcat中则不再使用BootStrap->Catalina这种方式进行启动,而是跨过这一层直接启动了Server。

二丶SpringBoot根据上下文推断ApplicationContext类型

1.推断当前webApplication类型

javax.servlet.Servlet,org.springframework.web.context.ConfigurableWebApplicationContext那么会视为SERVLET类型

2.获取webApplication类型对应ApplicationContext

AnnotationConfigServletWebServerApplicationContext内部类Factory和REACTIVE类型对应的AnnotationConfigReactiveWebServerApplicationContext内部类Factory。

AnnotationConfigServletWebServerApplicationContext内部类Factory去构建

三丶AnnotationConfigServletWebServerApplicationContext刷新触发tomcat启动

AnnotationConfigServletWebServerApplicationContext是AbstractApplicationContext的子类,其refresh刷新方法由AbstractApplicationContext进行了实现。大致流程如下

AnnotationConfigServletWebServerApplicationContext父类ServletWebServerApplicationContext进行了实现

四丶createWebServer创建web服务器

1.ServletWebServerFactory

WebServerFactory是一个标记接口,ServletWebServerFactory中定义了方法getWebServer(ServletContextInitializer... initializers来创建WebServer,如参ServletContextInitializer是函数式接口,具备方法onStartup来进行回调。

TomcatServletWebServerFactory来创建WebServer。

2.WebServer

3.创建TomcatWebServer流程

组装的过程依赖于Tomcat这个类提供的api

在Server中具备Service数组属性表示web应用服务器中众多的服务

    Connector

  • Engine

五丶TomcatWebServer启动Tomcat

六丶DispatcherServlet是怎么被加到tomcat中的

SpringBoot中如果使用web-stater,那么会引入DispatcherServlet的自动装配,这也就是为什么Tomcat接收到的请求会来到DispatcherServlet,然后由DispatcherServlet反射调用到Controller的方法。

DispatcherServlet是什么时候被加入到Tomcat中的呢?

TomcatReactiveWebServerFactory#configureContext方法中会注册TomcatStarterTomcatEmbeddedContext

TomcatEmbeddedContext是StandardContext的子类,在TomcatEmbeddedContext被调用start的时候,会拿出所有的ServletContainerInitializer调用其onStartup

TomcatStarter,TomcatStarter使用ServletContextInitializer数组记录了ServletWebServerApplicationContext#selfInitialize方法,从而实现ServletWebServerApplicationContext#selfInitialize的回调

ServletContainerInitializer是Servlet规范接口,而ServletContextInitializerSpringBoot定义的接口,利用TomcatStarter将SpringBoot定义的接口嫁接到Servlet定义的规范中从而保证当用户将SpringBoot打包成war包也能触发ServletWebServerApplicationContext#selfInitialize

ServletWebServerApplicationContext#selfInitialize做了什么

private void selfInitialize(ServletContext servletContext throws ServletException {
    // <1> 将当前 Spring 应用上下文设置到 ServletContext 上下文的属性中
    // 同时将 ServletContext 上下文设置到 Spring 应用上下文中
    prepareWebApplicationContext(servletContext;
    // <2> 向 Spring 应用上下文注册一个 ServletContextScope 对象(ServletContext 的封装)(这就是application这种bean作用域生效的本原因)
    registerApplicationScope(servletContext;
    // <3> 向 Spring 应用上下文注册 `contextParameters` 和 `contextAttributes` 属性
    WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(, servletContext;
    /**
     * <4> 【重点】先从 Spring 应用上下文找到所有的 ServletContextInitializer
     * 也就会找到各种  RegistrationBean,然后依次调用他们的 `onStartup` 方法,向 ServletContext 上下文注册 Servlet、Filter 和 EventListener
     * 例如 DispatcherServletAutoConfiguration DispatcherServletRegistrationBean 就会注册 @link DispatcherServlet 对象
      * 所以这里执行完了,也就启动了 Tomcat,同时注册了所有的 Servlet,那么 Web 应用准备就绪了
     */
    for (ServletContextInitializer beans : getServletContextInitializerBeans( {
        beans.onStartup(servletContext;
    }
}

Spring会从BeanFactory拿到所有ServletContextInitializer的实现

TomcatEmbeddedContext会将DispatcherServlet保证成Wrapper加入到TomcatEmbeddedContext中去。

七丶总结

这一波学习,让我深刻的理解了Tomcat容器模型,也了解到SpringBoot中使用Filter或者Servlet的时候,为什么要向Spring注入对应的RegsitrationBean,因为只有这样ServletWebServerApplicationContext才能从容器中获取到RegsitrationBean并注册到Tomcat中。

编程笔记 » SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

赞同 (122) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽