当前位置: 首页 > 科技观察

使用SpringBoot这么多年,你知道SpringBoot的Web类型推断是什么吗?

时间:2023-03-15 11:01:32 科技观察

使用SpringBoot这么多年,你知道SpringBoot的web类型推断是什么吗?估计很多小伙伴都不知道。毕竟开发做项目的时候,一般都是做普通的web项目,不需要特别了解。不过,本着学习的态度,今天阿芬就带大家看看什么是SpringBoot。网络类型推断。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/快速搭建三类项目。三类项目配置除了依赖是一样的,如下载后的项目文件所示Nonewebnonepom中对应的依赖为org.springframework.bootspring-boot-starterServletwebservlet下载后工程文件pom中对应的依赖为org.springframework.bootspring-boot-starter-webReactivewebreactive下载后项目文件pom中对应的依赖为org.springframework.bootspring-boot-starter-webflux接下来我们依次启动三个项目,看看有什么区别,启动Nonewebnone-web我们在日志中可以看到,在Noneweb类型下,应用开始运行后自动关闭,并且内置的网络服务器没有启动,也没有它监听任何端口。接下来我们看看另外两种web的启动日志。启动Servletwebservlet-web通过启动日志我们可以看到,这里启动了内置的TomcatServlet服务器,它监听8080端口,应用不会像None类型那样启动后自动关闭。启动Reactivewebreactive-web通过启动日志,我们可以看到这里启动了内置的Netty服务器,它监听8080端口(如果启动失败记得关闭上面的servletweb,否则端口会冲突).我们已经成功启动了所有三种类型的服务,那么接下来的问题是SpringBoot是如何确定使用哪种类型的呢?我们只是对这三个服务有不同的依赖关系,这显然与依赖关系有关。接下来,我们就来研究一下SpringBoot是如何实现的。SpringBootWeb类型推断原理我们在main方法中点击run方法,构造函数中publicstaticConfigurableApplicationContextrun(Class[]primarySources,String[]args){returnnewSpringApplication(primarySources).run(args);}我们可以看到有这么一行this.webApplicationType=WebApplicationType.deduceFromClasspath();根据属性名可以推断webtype是根据WebApplicationType.deduceFromClasspath();的静态方法判断的。接下来让我们看看这个方法的细节。如上图所示,可以看到SpringBoot底层通过ClassUtils.isPresent()方法判断对应的web类型类是否存在来判断web类型。之前的类路径下,如果org.springframework.web.reactive.DispatcherHandler存在,org.springframework.web.servlet.DispatcherServlet和org.glassfish.jersey.servlet.ServletContainer不存在,则说明当前应用web的类型是Reactive。当javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext中的任何一个都不存在时,说明当前应用是一个None类型的非web应用。否则,当前应用为Servlet类型。而我们再看ClassUtils.isPresent()这个方法,我们可以发现底层是通过className加载类路径上对应的类。如果存在,它将返回true。如果不存在,它将返回false。所以这也就解释了为什么我们只要在pom文件中添加相应的依赖就可以直接获取到对应的webtype,因为当我们在pom中添加相应的依赖时,类路径中就有之前判断的对应的类,然后通过ClassUtils.isPresent()判断当前应用属于哪种web类型。内置服务器是如何创建的知道了SpringBoot是如何进行web类型推断的,接下来的问题就是SpringBoot是如何根据web类型启动对应的内置web服务器的呢?这里我们以Reactiveweb为例进行调试和跟踪。首先我们在SpringApplication的run方法createApplicationContext()下一行打断,可以发现成功创建的context类型是AnnotationConfigReactiveWebServerApplicationContext。显然,到这一步,已经根据类型推断出了当前应用的web类型。它是Reactive的,会根据web的类型创建对应的ApplicationContext。reactive-web然后我们进入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。