美文网首页Spring Boot实践记录
Spring Boot Web容器初始化方式

Spring Boot Web容器初始化方式

作者: Jeff_tian | 来源:发表于2020-03-02 12:17 被阅读0次

Spring Boot容器另类的初始化过程

  • 对于Spring Boot应用来说,它并未使用SpringServletContainerInitializer来进行容器的初始化,而是使用了TomcatStarter进行的。
  • TomcatStarter存在三点因素使得它无法通过SPI机制进行初始化
    • 它没有不带参数的构造方法
    • 它的声明并非public
    • 其所在的jar包并没有META-INF/services目录
  • 所以TomcatStarter并非通过SPI机制进行的查找与实例化
  • 本质上,TomcatStarter是通过Spring Boot框架new出来的
  • 与SpringServletContainerInitializer类似,TomcatStarter在容器的初始化过程中也是扮演一个委托或是代理的角色,真正执行的初始化动作实际上是由它所持有的ServletContextInitializer的onStartup方法。

具体代码

  1. ServletContextInitializer
    package org.springframework.boot.web.servlet;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    
    import org.springframework.web.SpringServletContainerInitializer;
    import org.springframework.web.WebApplicationInitializer;
    
    /**
    * Interface used to configure a Servlet 3.0+ {@link ServletContext context}
    * programmatically. Unlike {@link WebApplicationInitializer}, classes that implement this
    * interface (and do not implement {@link WebApplicationInitializer}) will <b>not</b> be
    * detected by {@link SpringServletContainerInitializer} and hence will not be
    * automatically bootstrapped by the Servlet container.
    * <p>
    * This interface is primarily designed to allow {@link ServletContextInitializer}s to be
    * managed by Spring and not the Servlet container.
    * <p>
    * For configuration examples see {@link WebApplicationInitializer}.
    *
    * @author Phillip Webb
    * @since 1.4.0
    * @see WebApplicationInitializer
    */
    @FunctionalInterface
    public interface ServletContextInitializer {
    
        /**
        * Configure the given {@link ServletContext} with any servlets, filters, listeners
        * context-params and attributes necessary for initialization.
        * @param servletContext the {@code ServletContext} to initialize
        * @throws ServletException if any call against the given {@code ServletContext}
        * throws a {@code ServletException}
        */
        void onStartup(ServletContext servletContext) throws ServletException;
    
    }
    
  2. TomcatStarter
    /**
    * {@link ServletContainerInitializer} used to trigger {@link ServletContextInitializer
    * ServletContextInitializers} and track startup errors.
    *
    * @author Phillip Webb
    * @author Andy Wilkinson
    */
    class TomcatStarter implements ServletContainerInitializer {
    
        private static final Log logger = LogFactory.getLog(TomcatStarter.class);
    
        private final ServletContextInitializer[] initializers;
    
        private volatile Exception startUpException;
    
        TomcatStarter(ServletContextInitializer[] initializers) {
            this.initializers = initializers;
        }
    
        @Override
        public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
            try {
                for (ServletContextInitializer initializer : this.initializers) {
                    initializer.onStartup(servletContext);
                }
            }
            catch (Exception ex) {
                this.startUpException = ex;
                // Prevent Tomcat from logging and re-throwing when we know we can
                // deal with it in the main thread, but log for information here.
                if (logger.isErrorEnabled()) {
                    logger.error("Error starting Tomcat context. Exception: " + ex.getClass().getName() + ". Message: "
                            + ex.getMessage());
                }
            }
        }
    
        Exception getStartUpException() {
            return this.startUpException;
        }
    
    }
    
  3. 最终会通过TomcatStarter这个委托者,获取到所有的ServletContextInitializer实例数组,然后在onStartup方法中循环调用onStartup完成初始化的配置。

和传统Spring MVC之间的对应关系

  1. SpringServletContainerInitializer对应于TomcatStarter
  2. WebApplicationInitializer对应于ServletContextInitializer

为什么不统一

当我们运行启动命令java -jar的时候是不会调用javax.servlet.ServletContainerInitializer这个接口的

关于传统Spring MVC的web容器初始化方式可以参考Spring MVC容器初始化方式这篇文章

相关文章

网友评论

    本文标题:Spring Boot Web容器初始化方式

    本文链接:https://www.haomeiwen.com/subject/clfmkhtx.html