0
点赞
收藏
分享

微信扫一扫

springboot-嵌入式Servlet容器(Tomcat)源码分析以及容器切换

梦想家们 2022-01-11 阅读 71

目录

一、springboot的嵌入式Servlet容器(tomcat)

1.原理

2.源码

(1)ServletWebServerApplicationContext的createWebServer方法

(2)获取tomcat的webServer

(3)tomcat的启动方法

二、切换嵌入式Servlet容器

1.排除tomcat,添加undertow

2.启动时就会使用undertow(还是建议使用tomcat)


一、springboot的嵌入式Servlet容器(tomcat)

1.原理

(1)SpringBoot应用启动发现当前是Web应用。(web场景包starter会导入tomcat)

(2)web应用会创建一个web版的ioc容器 ServletWebServerApplicationContext。

(3)ServletWebServerApplicationContext  启动的时候寻找 ServletWebServerFactory(Servlet 的web服务器工厂---> 生产Servlet 的web服务器)。

(4)SpringBoot底层默认有很多的WebServer工厂;TomcatServletWebServerFactory, JettyServletWebServerFactory, UndertowServletWebServerFactory。

(5)SpringBoot底层直接会有一个自动配置类。ServletWebServerFactoryAutoConfiguration

(6)ServletWebServerFactoryAutoConfiguration导入了ServletWebServerFactoryConfiguration(配置类)

(7)ServletWebServerFactoryConfiguration 配置类 根据动态判断系统中到底导入了那个Web服务器的包。(默认是web-starter导入tomcat包),容器中就有TomcatServletWebServerFactory。

(8)TomcatServletWebServerFactory 创建出Tomcat服务器并启动;TomcatWebServer 的构造器拥有初始化方法initialize---会调用this.tomcat.start();

(9)内嵌服务器,就是手动把启动服务器的代码调用(前提是tomcat核心jar包存在)

2.源码

(1)ServletWebServerApplicationContext的createWebServer方法

// org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#createWebServer
private void createWebServer() {
   WebServer webServer = this.webServer; 
   ServletContext servletContext = getServletContext();
   if (webServer == null && servletContext == null) {
      // 获取ServletWebServerFactory,默认是tomcat的
      ServletWebServerFactory factory = getWebServerFactory();
      // 通过ServletWebServerFactory创建webServer
      this.webServer = factory.getWebServer(getSelfInitializer());
      getBeanFactory().registerSingleton("webServerGracefulShutdown",
            new WebServerGracefulShutdownLifecycle(this.webServer));
      getBeanFactory().registerSingleton("webServerStartStop",
            new WebServerStartStopLifecycle(this, this.webServer));
   }
   else if (servletContext != null) {
      try {
         getSelfInitializer().onStartup(servletContext);
      }
      catch (ServletException ex) {
         throw new ApplicationContextException("Cannot initialize servlet context", ex);
      }
   }
    // 启动tomcat
   initPropertySources();
}

(2)获取tomcat的webServer

// org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
   if (this.disableMBeanRegistry) {
      Registry.disableRegistry();
   }
   Tomcat tomcat = new Tomcat();
   File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
   tomcat.setBaseDir(baseDir.getAbsolutePath());
   Connector connector = new Connector(this.protocol);
   connector.setThrowOnFailure(true);
   tomcat.getService().addConnector(connector);
   customizeConnector(connector);
   tomcat.setConnector(connector);
   tomcat.getHost().setAutoDeploy(false);
   configureEngine(tomcat.getEngine());
   for (Connector additionalConnector : this.additionalTomcatConnectors) {
      tomcat.getService().addConnector(additionalConnector);
   }
   prepareContext(tomcat.getHost(), initializers);
   return getTomcatWebServer(tomcat);
}

(3)tomcat的启动方法

tomcat初始的时候就会调用start。

// org.springframework.boot.web.embedded.tomcat.TomcatWebServer#start
@Override
public void start() throws WebServerException {
   synchronized (this.monitor) {
      if (this.started) {
         return;
      }
      try {
         addPreviouslyRemovedConnectors();
         Connector connector = this.tomcat.getConnector();
         if (connector != null && this.autoStart) {
            performDeferredLoadOnStartup();
         }
         checkThatConnectorsHaveStarted();
         this.started = true;
         logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
               + getContextPath() + "'");
      }
      catch (ConnectorStartFailedException ex) {
         stopSilently();
         throw ex;
      }
      catch (Exception ex) {
         PortInUseException.throwIfPortBindingException(ex, () -> this.tomcat.getConnector().getPort());
         throw new WebServerException("Unable to start embedded Tomcat server", ex);
      }
      finally {
         Context context = findContext();
         ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
      }
   }
}

二、切换嵌入式Servlet容器

1.排除tomcat,添加undertow

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

2.启动时就会使用undertow(还是建议使用tomcat)

 

举报

相关推荐

0 条评论