使用SpringBoot内置web服务器

 更新时间:2021年9月26日 16:01  点击:1401

本文介绍SpringBoot内置web服务器。知识点有SpringBoot默认web服务器;如何配置当前web容器;内嵌Web服务器如何切换(从tomcat到jetty);Web容器怎么自动配置;web容器启动源码解析;SpringBoot内置服务器不使用SPI机制特别说明。

一、SpringBoot默认web服务器?

在SpringBoot中采用的默认web服务器是Tomcat,要了解为什么是Tomcat可从源码入手。

对于web服务器的配置,也是在自动配置中找,前面学习了SpringBoot自动配置WebMVC的知识,可以推测对于Web服务器的配置应该也是在一个自动配置类当中进行的,那么可以去/META-INF/spring.factories文件找一下WebMVC的自动配置,在这个自动配置内可以间接找到关于Web服务器的配置。

org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\

在上面SpringBoot包的目录找到这个路径下的Web服务器自动配置类。

这个Web服务器的自动配置类,我们可以看到这个配置类支持3种web服务器(Tomcat,Jetty,Undertow),具体要配置哪种服务器由ServletWebServerFactoryConfiguration来决定,同时这里还定义了一个顺序,依次是Tomcat->Jetty->Undertow。

那要选择哪种服务器呢?看ServletWebServerFactoryConfiguration。

在这个web服务器工厂配置类中,分别对上述三种服务器进行了定义:

对Tomcat定义:判断环境中是否引入了Tomcat所需的依赖Servlet.class, Tomcat.class, UpgradeProtocol.class,同时用户没有自己进行Web服务器配置(比如自己通过实现ServletWebServerFactory接口进行手动配置web服务器),那么这个Tomcat服务器就会生效。

对Jetty定义:所需要的依赖有Servlet.class, Server.class, Loader.class, WebAppContext.class

对Undertow定义:所需要的依赖有Servlet.class, Undertow.class, SslClientAuthMode.class

那么问题来了,SpringBoot如果这几种都有,那是怎么选择呢?从ServletWebServerFactoryAutoConfiguration配置类

@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
      ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
      ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
      ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration 

通过@Import就可以看出这里定义了一个顺序,依次是Tomcat->Jetty->Undertow,意思就是当环境中有Tomcat满足的依赖时就会优先使用Tomcat,依次往后推。

而一般情况下,在SpringBoot依赖中默认就已经引入tomcat的依赖,因此这里对于tomcat来说一般情况下会恒成立,那么Tomcat就会一直作为恒成立条件被SpringBoot首选为默认服务器。

二、如何配置当前web容器?

想要配置当前Web容器,可以通过yml配置让SpringBoot自动加载解析修改配置,也可以通过提供自定义的@Bean方法忽略SpringBoot自动配置采用手动配置方式。

为什么是通过@Bean提供ServletWebServerFactory和WebServerFactoryCustomizer的Bean交给Spring就可以跳过SpringBoot的自动web服务器配置呢?可从源码分析如下:

对于WebServerFactoryCustomizer在上面ServletWebServerFactoryConfiguration配置类Factory配置Tomcat,Jetty时在注解上会判断存过存在自己手动添加的ServletWebServerFactory则不再进行自动配置:

对于WebServerFactoryCustomizer则在ServletWebServerFactoryAutoConfiguration服务器自动配置类加载时,如果存在自己定义的WebServerFactoryCustomizer,那么就会触发一个WebServerFactoryCustomizerBeanPostProcessor后置处理器,在这个后置处理器中会遍历这些WebServerFactoryCustomizer并且执行内部customize方法,从而跳过自动配置,转为进行自定义配置:

三、内嵌Web服务器如何切换(从tomcat到jetty)?

上面通过源码可以知道一般情况下,Tomcat会一直作为恒成立条件被SpringBoot首选为默认服务器。

但是我们如果不想用Tomcat作为默认服务器,例如想切换为Jetty,那么我们应该怎么办呢?

我们可以把Tomcat的相关依赖在pom.xml中的spring-boot-starter-web中剔除掉,使环境不再拥有Tomcat依赖,同时加入Jetty的依赖那么就能使Jetty作为满足条件被SpringBoot选择了。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!-- 剔除Tomcat -->
    <exclusions>
        <exclusion>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <groupId>org.springframework.boot</groupId>
        </exclusion>
    </exclusions>
</dependency>
 
<!-- 加入jetty -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

这样,SpringBoot重新启动后就会切换为Jetty服务器了。

四、Web容器怎么自动配置?

对于Web容器的自动配置,以Tomcat未来可以看上面提到的TomcatServletWebServerFactory,这是通过@Bean自动注入一个Tomcat的工厂类:

这个工厂类内部会对Tomcat进行一些初始化操作,最重要的操作在getWebServer方法内:

首先这个类是SpringBoot包提供的,用的是最底层的tomcat实例进行配置(通过new Tomcat的方式,而这个Tomcat是tomcat源码包的一个实例类 package org.apache.catalina.startup),具体的配置细节不做描述,主要对端口,协议,tomcat组件对象等进行初始化并封装:

将要发布的Web应用信息Context初始化到tomcat中:

对初始化好的tomcat进行封装并启动:

最后将这个tomcat对象封装为一个TomcatWebServer对象供SpringBoot启动时调用。

综上,web容器的自动配置,实际上是SpringBoot通过创建原生Tomcat对象,对这个对象进行端口,协议,组件等初始化,并且将Web应用信息Context对象封装到这个tomcat对象中,然后Web应用信息配置生命周期监听生效后启动tomcat,最后将这个过程

封装到一个WebServer对象中供SpringBoot启动时调用。

五、web容器启动源码解析?

SpringBoot是什么时候运行了一个web服务器呢?这个要从SpringBootApplication.run()方法进行分析。以tomcat为例按照上面提到的,这个启动过程应该会调用到TomcatServletWebServerFactory.getWebServer方法获取这么一个tomcat实例。

调用链可看下面图示:

SpringBootApplication.run():

context = createApplicationContext():创建Context环境,这个方法内会根据当前环境初始化不同的Context,如果是Web环境则会初始化出AnnotationConfigServletWebApplicationContext:

初始化AnnotationConfigServletWebApplicationContext之后,在构造函数调用这个context的refresh方法-->onRefresh方法:

调用onRefresh方法,就会调用到ServletWebServerApplicationContext的onRefresh方法,在这个方法内,就对web服务器进行了创建操作createWebServer():

在createWebServer()方法中,会判断是外置还是内置方式发布应用,分别进行不同的逻辑操作。我们这里以内置来学习:

这样,SpringBoot启动时在创建Web服务器时,就执行到了getWebServer的操作,然后再对Web服务器进行创建,初始化和启动操作。

综上:在SpringBoot的run启动时,会判断当前所处环境。

如果是Web环境则通过创建一个ServletWebServerApplicationContext,执行构造函数的refresh方法,在refresh方法内重写onRefresh方法,执行创建createWebServer()方法,这个方法会根据当前应用是内置还是外置发布方式来决定以何种方式获取web服务器。

如果是内置方式则通过TomcatServletWebServerFactory工厂类来获取一个首选的web服务器,然后进行服务器的初始化配置,应用加载生效以及服务器启动的操作。

六、SpringBoot内置服务器不使用SPI机制特别说明?

最后还有一个结论要记住:对于SpringBoot内置服务器不会通过SPI的机制(官网也有特别说明),因为SpringBoot内置服务器是SpringBoot自己帮我们创建了web服务器来发布应用,不使用SPI机制的目的就是尽可能减少内置和外置web服务器可能存在的冲突,让web应用由SpringBoot自己来管理。详细原因和原理这里不做研究。

至此,关于SpringBoot内置服务器的相关知识解析就到此了。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • 解决springboot使用logback日志出现LOG_PATH_IS_UNDEFINED文件夹的问题

    这篇文章主要介绍了解决springboot使用logback日志出现LOG_PATH_IS_UNDEFINED文件夹的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-28
  • Springboot如何实现Web系统License授权认证

    这篇文章主要介绍了Springboot如何实现Web系统License授权认证,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-05-28
  • C#使用Http Post方式传递Json数据字符串调用Web Service

    这篇文章主要为大家详细介绍了C#使用Http Post方式传递Json数据字符串调用Web Service,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • SpringBoot实现excel文件生成和下载

    这篇文章主要为大家详细介绍了SpringBoot实现excel文件生成和下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-09
  • 详解springBoot启动时找不到或无法加载主类解决办法

    这篇文章主要介绍了详解springBoot启动时找不到或无法加载主类解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-16
  • SpringBoot集成Redis实现消息队列的方法

    这篇文章主要介绍了SpringBoot集成Redis实现消息队列的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-10
  • 分享一段php获取linux服务器状态的代码

    简单的php获取linux服务器状态的代码,不多说-直接上函数:复制代码 代码如下:function get_used_status(){ $fp = popen('top -b -n 2 | grep -E "^(Cpu|Mem|Tasks)"',"r");//获取某一时刻系统cpu和内存使用情况 $rs =...2014-05-31
  • InterlliJ IDEA2020新建java web项目找不到Static Web的解决

    这篇文章主要介绍了InterlliJ IDEA2020新建java web项目找不到Static Web的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-02
  • 解决Springboot get请求是参数过长的情况

    这篇文章主要介绍了解决Springboot get请求是参数过长的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17
  • Spring Boot项目@RestController使用重定向redirect方式

    这篇文章主要介绍了Spring Boot项目@RestController使用重定向redirect方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-02
  • Springboot+TCP监听服务器搭建过程图解

    这篇文章主要介绍了Springboot+TCP监听服务器搭建过程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-10-28
  • springBoot 项目排除数据库启动方式

    这篇文章主要介绍了springBoot 项目排除数据库启动方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-10
  • 服务器 UDP端口占用几千个的解决办法

    前一段时间使用NetStat命令查看服务器端口时,发现服务器udp端口开放了好多,最少在1000个以上,当时事情比较多,没有管它,今天终于有点时间,仔细检查了一下,排除了这个问题. ...2016-01-27
  • 详解在IDEA中将Echarts引入web两种方式(使用js文件和maven的依赖导入)

    这篇文章主要介绍了在IDEA中将Echarts引入web两种方式(使用js文件和maven的依赖导入),本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-07-11
  • jQuery mobile 移动web(6)

    这篇文章主要介绍了jQuery mobile 移动web(6)的相关资料,需要的朋友可以参考下...2015-12-21
  • PHP连接公司内部服务器的MYSQL数据库的简单实例

    “主机,用户名,密码”得到连接、“数据库,sql,连接”得到结果,最后是结果的处理显示。当然,数据库连接是扩展库为我们完成的,我们能做的仅仅是处理结果而已。...2013-09-29
  • springboot中使用@Transactional注解事物不生效的坑

    这篇文章主要介绍了springboot中使用@Transactional注解事物不生效的原因,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-26
  • SpringBoot接口接收json参数解析

    这篇文章主要介绍了SpringBoot接口接收json参数解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-19
  • 详解SpringBoot之访问静态资源(webapp...)

    这篇文章主要介绍了详解SpringBoot之访问静态资源(webapp...),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-14
  • 解决HttpPost+json请求---服务器中文乱码及其他问题

    这篇文章主要介绍了解决HttpPost+json请求---服务器中文乱码及其他问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-22