我的编程空间,编程开发者的网络收藏夹
学习永远不晚

SpringBoot 嵌入式web容器的启动原理详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

SpringBoot 嵌入式web容器的启动原理详解

SpringBoot应用启动run方法

SpringApplication.java 中执行的代码


@SpringBootApplication
@EnableAsync //使用异步注解@Async 需要在这里加上@EnableAsync
@MapperScan("springboot.dao") //不可或缺作用是扫描dao包下面的所有mapper装配
public class HelloApplication {
    public static void main(String[] args) {
        SpringApplication.run(HelloApplication.class,args);
    }
}

    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class[]{primarySource}, args);
    }

    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

在这里插入图片描述


 private void refreshContext(ConfigurableApplicationContext context) {
        this.refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
            }
        }

    protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        ((AbstractApplicationContext)applicationContext).refresh();
    }

ServletWebServerApplicationContext.java执行的方法


    public final void refresh() throws BeansException, IllegalStateException {
        try {
            super.refresh();
        } catch (RuntimeException var2) {
            this.stopAndReleaseWebServer();
            throw var2;
        }
    }

    protected void onRefresh() {
        super.onRefresh();
        try {
            this.createWebServer();
        } catch (Throwable var2) {
            throw new ApplicationContextException("Unable to start web server", var2);
        }
    }

 private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = this.getServletContext();
        if (webServer == null && servletContext == null) {
            ServletWebServerFactory factory = this.getWebServerFactory();
            this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
        } else if (servletContext != null) {
            try {
                this.getSelfInitializer().onStartup(servletContext);
            } catch (ServletException var4) {
                throw new ApplicationContextException("Cannot initialize servlet context", var4);
            }
        }
        this.initPropertySources();
    }

    protected ServletWebServerFactory getWebServerFactory() {
        String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
        if (beanNames.length == 0) {
            throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.");
        } else if (beanNames.length > 1) {
            throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
        } else {
            return (ServletWebServerFactory)this.getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
        }
    }

    //配置嵌入式的servlet容器
    @Bean
    public WebServerFactoryCustomizer<ConfigurableWebServerFactory> MyCustomizer(){
        return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
            @Override
            public void customize(ConfigurableWebServerFactory factory) {
                factory.setPort(8081);
            }
        };
    }

SpringBoot 2.x 版本

嵌入式Servlet容器自动配置原理以及启动原理

一、版本说明

Spring Boot 2.x 版本的嵌入式Servlet容器自动配置是通过 WebServerFactoryCustomizer定制器 来定制的,而在Spring Boot 1.x 版本中我们是通过 EmbeddedServletContainerCustomizer 嵌入式的Servlet容器定制器来定制的。由于之前看的资料都是1.x的版本,但是我使用的是2.x,所以在这里记录一下2.x版本的嵌入式Servlet容器自动配置原理以及启动原理。

二、总结

嵌入式Servlet容器自动配置原理以及启动原理有三大步:

步骤:

  • SpringBoot 根据导入的依赖信息,自动创建对应的 WebServerFactoryCustomizer(web服务工厂定制器);
  • WebServerFactoryCustomizerBeanPostProcessor(web服务工厂定制器组件的后置处理器)获取所有类型为web服务工厂定制器的组件(包含实现WebServerFactoryCustomizer接口,自定义的定制器组件),依次调用customize()定制接口,定制Servlet容器配置;
  • 嵌入式的Servlet容器工厂创建tomcat容器,初始化并启动容器。

三、嵌入式Servlet容器自动配置原理(以Tomcat为例)

1、首先找到 EmbeddedWebServerFactoryCustomizerAutoConfiguration ,在里面我们可以看到SpringBoot支持的 servlet容器


//SprinBoot支持的servlet容器有三个Tomcat、Jetty、Undertow,但是默认配置的是Tomcat
 
 
//嵌入式的Undertow
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({Undertow.class, SslClientAuthMode.class})
    public static class UndertowWebServerFactoryCustomizerConfiguration {
        public UndertowWebServerFactoryCustomizerConfiguration() {
        }
 
        @Bean
        public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
            return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
        }
    }
 
 
//嵌入式的Jetty
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({Server.class, Loader.class, WebAppContext.class})
    public static class JettyWebServerFactoryCustomizerConfiguration {
        public JettyWebServerFactoryCustomizerConfiguration() {
        }
 
        @Bean
        public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
            return new JettyWebServerFactoryCustomizer(environment, serverProperties);
        }
    }
 
//嵌入式的Tomcat
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({Tomcat.class, UpgradeProtocol.class})
    public static class TomcatWebServerFactoryCustomizerConfiguration {
        public TomcatWebServerFactoryCustomizerConfiguration() {
        }
 
        @Bean
        public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
            return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
        }
    }

2、准备环节

1)在以下位置打一个断点

2)、点进 TomcatWebServerFactoryCustomizer 也就是上图 return 的,然后在里面的如下位置打一个断点

3)、然后在里面debug程序,我们在控制台就可以看到如下信息

3、按照上图从下往上分析。我们启动springboot应用时,都是直接运行主程序的main方法,然后调用里面的run方法,如下图

4、调用完run方法,回来到 refreshContext 方法,这个方法是帮我们创建IOC容器对象,并且初始化容器创建容器中的每一个组件

5、在调用了 reflesh 方法刷新刚才的IOC容器后,来到 onreflesh 方法,调用createWebServer()方法,创建WebServer

6、来到createWebServer()方法,该方法最终能够获取到一个与当前应用(也就是总结里说的第一步,根据我们导入的依赖来获取)所导入的Servlet类型相匹配的web服务工厂,通过工厂就可以获取到相应的 WebServerFactoryCustomizer (Web服务工厂定制器)

注:createWebServer()执行后,我们其实来到了 EmbeddedWebServerFactoryCustomizerAutoConfiguration,然后根据条件(配置的依赖)配置哪一个Web服务器

我们通过查看 ServletWebServerFactory 的子类,可以看到其中三个就是Tomcat、Jetty和Undertow,根据我们的配置,所以这里获取到的是 TomcatWebServerFactoryCustomizer

至此,TomcatWebServerFactoryCustomizer组件创建完成,对应的服务配置类也已添加到IOC容器。

7、因为容器中某个组件要创建对象就会惊动后置处理器 然后就到 WebServerFactoryCustomizerBeanPostProcessor(web服务工厂定制器组件的后置处理器),该类负责在bean组件初始化之前执行初始化工作。它先从IOC容器中获取所有类型为WebServerFactoryCustomizerBeans(web服务工厂定制器的组件)

通过后置处理器获取到的TomcatWebServerFactoryCustomizer调用customize()定制方法,获取到Servlet容器相关配置类ServerProperties,进行自动配置

至此,嵌入式Servlet容器的自动配置完成。

注:从源码分析可以得出配置嵌入式Servlet容器的两种解决方案:

1、在全局配置文件中,通过server.xxx来修改和server有关的配置:


server.port=8081
server.tomcat.xxx...

2、实现WebServerFactoryCustomizer接口,重写它的customize()方法,对容器进行定制配置:


@FunctionalInterface
public interface WebServerFactoryCustomizer<T extends WebServerFactory> {
    void customize(T factory);
}

四、嵌入式Servlet容器启动原理(以Tomcat为例)

1、应用启动后,根据导入的依赖信息,创建了相应的Servlet容器工厂,创建了TomcatServletWebServerFactory,调用getWebServer()方法创建Tomcat容器:(其实就是重写了ServletWebServerFactory里面的getWebServer方法

找到下面的getTomcatWebServer方法

2、然后点进去分析TomcatWebServer的有参构造器,执行 initialize() 方法

3、点进去就可以发现,里面通过调用start方法来启动Tomcat

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

SpringBoot 嵌入式web容器的启动原理详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

SpringBoot嵌入式web容器的启动原理是什么

这篇文章将为大家详细讲解有关SpringBoot嵌入式web容器的启动原理是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。SpringBoot应用启动run方法SpringApplication.ja
2023-06-25

SpringBoot嵌入式Web容器原理与使用介绍

Web开发的核心内容主要包括内嵌的Servlet容器和SpringMVCSpringBoot使用起来非常简洁,大部分配置都有SpringBoot自动装配,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2022-11-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录