一直用SpringBoot这么多年,那么你知道SpringBoot的web类型推断是什么吗?估计很多小伙伴都不知道。毕竟开发做项目的时候,一般都是做普通的web项目,不需要特别了解。不过,本着学习的态度,阿芬给大家介绍一下SpringBoot的web类型推断。SpringBoot的web类型有哪些?既然是web类型推断,那么我们就必须知道SpringBoot支持哪些类型,然后才能分析类型推断是如何进行的。根据官方介绍,SpringBoot的web类型一共有三种,分别是NONE、SERVLET和REACTIVE,定义在枚举WebApplicationType中。这三种类型代表三种含义:NONE:不是web应用,不需要启动内置的web服务器;SERVLET:基于servlet的web应用需要启动一个内置的servlet服务器;REACTIVE:一个反应式Web应用程序需要启动一个内置的反应式服务器;publicenumWebApplicationType{NONE,SERVLET,REACTIVE;}web类型推断上面提到了SpringBoot的三种web类型。下面我们通过代码来验证一下,再分析一下SpringBoot是如何进行类型推断的。首先我们在https://start.spring.io/快速搭建三类项目。三类项目的配置除了依赖外都是一样的,如Noneweb下载后的项目文件所示pom中对应的依赖为org.springframework.bootspring-boot-starter从Servletweb下载的工程文件pom中对应的依赖为org.springframework.bootspring-boot-starter-webReactiveweb下载后项目文件pom中对应的依赖为org.springframework.bootspring-boot-starter-webflux接下来我们依次启动这三个项目,看看有什么区别,通过启动日志启动Noneweb我们可以看到,在Noneweb类型下,应用开始运行后自动关闭,并且内置的网络服务器没有启动,也没有监听任何端口。接下来我们看看另外两种web的启动日志。启动Servletweb通过启动日志我们可以看到这里启动了内置的TomcatServlet服务器,监听8080端口,应用不会像None类型那样启动后自动关闭。启动Reactiveweb通过启动日志我们可以看到这里启动了内置的Nettyserver,监听8080端口(如果启动失败记得关闭上面的servletweb,否则端口会冲突)。我们已经成功启动了所有三种类型的服务,那么接下来的问题是SpringBoot是如何确定使用哪种类型的呢?我们只是对这三个服务有不同的依赖关系,这显然与依赖关系有关。接下来,我们就来研究一下SpringBoot是如何实现的。SpringBootWeb类型推断原理我们在main方法中点击run方法,构造函数中publicstaticConfigurableApplicationContextrun(Class>[]primarySources,String[]args){returnnewSpringApplication(primarySources).run(args);}我们可以看到有这么一行this.webApplicationType=WebApplicationType.deduceFromClasspath();根据属性名我们可以推断web类型是根据WebApplicationType.deduceFromClasspath()这个静态方法判断的;接下来让我们看看这个方法的细节。如上图所示,可以看出SpringBoot底层通过ClassUtils.isPresent()方法判断对应的web类型类是否存在来判断web类型。在之前的类路径下,如果org.springframework.web.reactive.DispatcherHandler存在,org.springframework.web.servlet.DispatcherServlet和org.glassfish.jersey.servlet.ServletContainer不存在,则说明当前应用web类型为反应性。当javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext中的任何一个都不存在时,说明当前应用是一个None类型的非web应用。否则,当前应用程序是Servlet类型。而我们再看ClassUtils.isPresent()方法可以发现,底层是通过className在类路径上加载对应的类,存在则返回true,不存在则返回false。所以这也就解释了为什么我们只要在pom文件中添加对应的依赖就可以直接获取到对应的web类型,因为我们在pom中添加对应的依赖时,前面判断的对应的类存在于类路径中,然后使用ClassUtils.isPresent()来确定当前应用程序属于哪种Web类型。内置服务器是如何创建的知道了SpringBoot是如何推断web类型的,接下来的问题就是SpringBoot是如何根据web类型启动对应的内置web服务器的呢?这里我们以Reactiveweb为例进行调试和跟踪。首先我们在SpringApplication的run方法createApplicationContext()下一行打断,可以发现成功创建的context类型是AnnotationConfigReactiveWebServerApplicationContext。显然,到这一步,已经根据类型推断出了当前应用的web类型。Reactive,并根据webType创建对应的ApplicationContext。然后我们进入org.springframework.boot.SpringApplication#refreshContext方法,终于可以进入org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext#refresh方法,因为AnnotationConfigReactiveWebServerApplicationContext继承了ReactiveWebServerApplicationContext。继续通过引用关系,我们可以找到org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext#onRefresh这个方法,在这个方法中我们会找到如下代码,这里会创建一个webServer。具体的创建方法在WebServerManager中,继续往下看可以找到createHttpServer()方法。在createHttpServer()方法中,创建了HttpServer,并绑定了默认的8080端口。具体过程如下页所示。有兴趣的可以自行跟踪调试。至此,一个Reactive内置服务器就创建成功了,同一个Servlet服务器类似。总结Spring的出现给Java程序员带来了春天,SpringBoot框架的出现大大加快了程序员的开发效率。然而很多时候我们利用她的便利却缺乏对底层系统实现的把握。希望本文能帮助大家对SpringBoot有更好的了解。