SpringBoot 的 web 类型有三种,分别是,NONE、SERVLET 和 REACTIVE,定义在枚举 WebApplicationType 中,这三种类型分别代表了三种含义:

NONE:不是一个 web 应用,不需要启动内置的 web 服务器;SERVLET:基于 servlet 的 web 应用,需要启动一个内置的 servlet 服务器;REACTIVE:一个 reactive 的 web 应用,需要启动一个内置的 reactive 服务器;

servlet和reactive区别

servlet:同步阻塞式

reactive:异步非阻塞式

上图我们可以清晰地区分出基于Servlet api和Reactive各自的技术栈结构,不过在最上层,Spring都给我们封装成了我们在SpringMVC中使用的基于注解的Web层api。

pom依赖

None web:

org.springframework.boot

spring-boot-starter

Servlet web:

org.springframework.boot

spring-boot-starter-web

Reactive web:

org.springframework.boot

spring-boot-starter-webflux

启动结果

None web 类型下,应用启动运行后就自动关闭了,并没有启动内置的 web 服务器,也没有监听任何端口。

Servlet web 类型下,启动了内置的 Tomcat Servlet 服务器,监听了 8080 端口,应用程序并不会像 None 类型一样,启动后就自动关闭。

Reactive web类型下,启动了内置的 Netty 服务器,并监听在 8080 端口上。

启动源码解析

protected ConfigurableApplicationContext createApplicationContext() {

return this.applicationContextFactory.create(this.webApplicationType);

}

applicationContextFactory有三个实现类:

根据WebApplicationType来判断进入哪个类的create方法。

webApplicationType初始化

public enum WebApplicationType {

NONE,

SERVLET,

REACTIVE;

private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};

private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";

private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";

private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

private WebApplicationType() {

}

static WebApplicationType deduceFromClasspath() {

if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {

return REACTIVE;

} else {

String[] var0 = SERVLET_INDICATOR_CLASSES;

int var1 = var0.length;

for(int var2 = 0; var2 < var1; ++var2) {

String className = var0[var2];

if (!ClassUtils.isPresent(className, (ClassLoader)null)) {

return NONE;

}

}

return SERVLET;

}

}

}

在当前类路径下面如果当 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 文件中只要加入对应的依赖就可以直接得到相应的 web 类型了,因为当我们在 pom 中加入相应的依赖过后,类路径里面就存在了前面判断的对应的类,再通过 ClassUtils.isPresent() 就判断出来当前应用属于那种 web 类型了。

以servlet为例:

根据继承关系找到ServletWebServerApplicationContext类,其中onRefresh方法中调用了createWebServer方法

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) {

StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");

ServletWebServerFactory factory = this.getWebServerFactory();

createWebServer.tag("factory", factory.getClass().toString());

//根据ServletContextInitializer确定创建server的类型

this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});

createWebServer.end();

this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));

this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));

} else if (servletContext != null) {

try {

this.getSelfInitializer().onStartup(servletContext);

} catch (ServletException var5) {

throw new ApplicationContextException("Cannot initialize servlet context", var5);

}

}

this.initPropertySources();

}

比如TomcatServletWebServerFactory中就创建了tomcat服务器

public WebServer getWebServer(ServletContextInitializer... initializers) {

if (this.disableMBeanRegistry) {

Registry.disableRegistry();

}

Tomcat tomcat = new Tomcat();

File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");

tomcat.setBaseDir(baseDir.getAbsolutePath());

Iterator var4 = this.serverLifecycleListeners.iterator();

while(var4.hasNext()) {

LifecycleListener listener = (LifecycleListener)var4.next();

tomcat.getServer().addLifecycleListener(listener);

}

Connector connector = new Connector(this.protocol);

connector.setThrowOnFailure(true);

tomcat.getService().addConnector(connector);

this.customizeConnector(connector);

tomcat.setConnector(connector);

tomcat.getHost().setAutoDeploy(false);

this.configureEngine(tomcat.getEngine());

Iterator var8 = this.additionalTomcatConnectors.iterator();

while(var8.hasNext()) {

Connector additionalConnector = (Connector)var8.next();

tomcat.getService().addConnector(additionalConnector);

}

this.prepareContext(tomcat.getHost(), initializers);

return this.getTomcatWebServer(tomcat);

}

文章链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: