其他分享
首页 > 其他分享> > SpringBoot--嵌入式Servlet容器

SpringBoot--嵌入式Servlet容器

作者:互联网

一、嵌入式Servlet容器

在传统的Web开发中,需要将项目打成 war 包,在外部配置部署好 Tomcat 服务器,而这个 Tomcat 就是 Servlet 容器,在使用 SpringBoot 开发时,我们无需再外部部署 Servlet 容器,使用的是嵌入式(内置) Servlet 容器( Tomcat ),如果我们使用嵌入式 Servlet 容器,存在以下问题:

二、注册 Servlet 、 Filter 、 Listener

三、嵌入式 Servlet 容器的自动配置原理

在 SpringBoot 中拥有如下自动配置类 EmbeddedServletContainerAutoConfiguration :

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {}
/**
    * Nested configuration if Tomcat is being used.
    */
   @Configuration
   @ConditionalOnClass({ Servlet.class, Tomcat.class })
   @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
   public static class EmbeddedTomcat {

       @Bean
       public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
           return new TomcatEmbeddedServletContainerFactory();
       }

   }
public interface EmbeddedServletContainerFactory {
   /**
   Gets a new fully configured but paused {@link EmbeddedServletContainer} instance.
   Clients should not be able to connect to the returned server until
   {@link EmbeddedServletContainer#start()} is called (which happens when the
   {@link ApplicationContext} has been fully refreshed).
   @param initializers {@link ServletContextInitializer}s that should be applied as
   the container starts
   @return a fully configured and started {@link EmbeddedServletContainer}
   @see EmbeddedServletContainer#stop()
    */
   /**
   获取一个新的完全配置但暂停的 {@link EmbeddedServletContainer} 实例。
   在调用 {@link EmbeddedServletContainer#start()} 之前,客户端应该无法连接到返回的服务器(这在 	{@link ApplicationContext} 已完全刷新时发生)。
   @param 初始化器 {@link ServletContextInitializer} 应在容器启动时应用 
   @return 完全配置并启动 {@link EmbeddedServletContainer} 
   @see EmbeddedServletContainer#stop()
    */
   EmbeddedServletContainer getEmbeddedServletContainer(
           ServletContextInitializer... initializers);

}

image

@Override
   public EmbeddedServletContainer getEmbeddedServletContainer(
           ServletContextInitializer... initializers) {
       Tomcat tomcat = new Tomcat();
       File baseDir = (this.baseDirectory != null ? this.baseDirectory
               : createTempDir("tomcat"));
       tomcat.setBaseDir(baseDir.getAbsolutePath());
       Connector connector = new Connector(this.protocol);
       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 getTomcatEmbeddedServletContainer(tomcat);
   }
/**
Create a new {@link TomcatEmbeddedServletContainer} instance.
@param tomcat the underlying Tomcat server
@param autoStart if the server should be started
*/
/**
创建一个新的 {@link TomcatEmbeddedServletContainer} 实例。
@param tomcat 底层是 Tomcat 服务器 
@param autoStart 是否应该启动服务器
*/
   public TomcatEmbeddedServletContainer(Tomcat tomcat, boolean autoStart) {
       Assert.notNull(tomcat, "Tomcat Server must not be null");
       this.tomcat = tomcat;
       this.autoStart = autoStart;
       initialize();
   }

   private void initialize() throws EmbeddedServletContainerException {
       TomcatEmbeddedServletContainer.logger
               .info("Tomcat initialized with port(s): " + getPortsDescription(false));
       synchronized (this.monitor) {
           try {
               addInstanceIdToEngineName();
               try {
                   // Remove service connectors to that protocol binding doesn't happen yet
                   // 尚未删除与该协议绑定的服务连接器
                   removeServiceConnectors();

                   // Start the server to trigger initialization listeners
                   // 启动服务器触发初始化监听器
                   this.tomcat.start();

                   // We can re-throw failure exception directly in the main thread
                   // 我们可以直接在主线程中重新抛出失败异常
                   rethrowDeferredStartupExceptions();

                   Context context = findContext();
                   try {
                       ContextBindings.bindClassLoader(context, getNamingToken(context),
                               getClass().getClassLoader());
                   }
                   catch (NamingException ex) {
                       // Naming is not enabled. Continue
                       // 未启用命名。继续
                   }

                   // Unlike Jetty, all Tomcat threads are daemon threads. We create a blocking non-daemon to stop immediate shutdown
                   
                   // 与 Jetty 不同,所有 Tomcat 线程都是守护线程。我们创建一个阻塞的非守护进程来停止立即关闭
                   startDaemonAwaitThread();
               }
               catch (Exception ex) {
                   containerCounter.decrementAndGet();
                   throw ex;
               }
           }
           catch (Exception ex) {
               throw new EmbeddedServletContainerException(
                       "Unable to start embedded Tomcat", ex);
           }
       }
   }

四、嵌入式 Servlet 容器启动原理

获取嵌入式 Servlet 容器工厂:

五、使用外置的 Servlet 容器

嵌入式 Servlet 容器

  • 优点:简单、快捷
  • 缺点:默认不支持JSP,优化定制复杂(使用定制器,自定义配置 Servlet 容器的创建工厂)

外部的 Servlet 容器:外面安装 Tomcat -应用 war 包的方式打包

我们使用 war 包的形式创建 SpringBoot 工程可以发现其目录结构如下:

image

image

image

image

六、外置 Servlet 容器的启动原理

参考博客:https://www.cnblogs.com/skykuqi/p/12000060.html

标签:容器,SpringBoot,Tomcat,--,嵌入式,import,Servlet,public
来源: https://www.cnblogs.com/cxy-lxl/p/16609238.html