spring boot中servlet启动原理

启动过程及原理

1 spring boot 应用启动运行run方法

复制代码
StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            Banner printedBanner = printBanner(environment);
                       //创建一个ApplicationContext容器
            context = createApplicationContext();
            analyzers = new FailureAnalyzers(context);
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
                      //刷新IOC容器
            refreshContext(context);
            afterRefresh(context, applicationArguments);
            listeners.finished(context, null);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            return context;
        }
        catch (Throwable ex) {
            handleRunFailure(context, listeners, analyzers, ex);
            throw new IllegalStateException(ex);
        }     
复制代码

2  createApplicationContext():创建IOC容器,如果是web应用则创建AnnotationConfigEmbeddedWebApplacation的IOC容器,如果不是,则创建AnnotationConfigApplication的IOC容器

复制代码
    public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
            + "annotation.AnnotationConfigApplicationContext";
</span><span style="color: #008000;">/*</span><span style="color: #008000;">*
 * The class name of application context that will be used by default for web
 * environments.
 </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> final String DEFAULT_WEB_CONTEXT_CLASS = <span style="color: #800000;">"</span><span style="color: #800000;">org.springframework.</span><span style="color: #800000;">"</span>
        + <span style="color: #800000;">"</span><span style="color: #800000;">boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext</span><span style="color: #800000;">"</span><span style="color: #000000;">;

protected ConfigurableApplicationContext createApplicationContext() {
Class
<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
          //根据应用环境,创建不同的IOC容器
contextClass
= Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}

复制代码

3    refreshContext(context) spring boot刷新IOC容器(创建容器对象,并初始化容器,创建容器每一个组件)

复制代码
private void refreshContext(ConfigurableApplicationContext context) {
        refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            }
            catch (AccessControlException ex) {
                // Not allowed in some environments.
            }
        }
    }
复制代码

4 refresh(context);刷新刚才创建的IOC容器

protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        ((AbstractApplicationContext) applicationContext).refresh();
    }

5 调用父类的refresh()的方法

复制代码
public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);
        </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.postProcessBeanFactory(beanFactory);
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.invokeBeanFactoryPostProcessors(beanFactory);
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.registerBeanPostProcessors(beanFactory);
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.initMessageSource();
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.initApplicationEventMulticaster();
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.onRefresh();
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.registerListeners();
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.finishBeanFactoryInitialization(beanFactory);
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.finishRefresh();
        } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (BeansException var9) {
            </span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">this</span><span style="color: #000000;">.logger.isWarnEnabled()) {
                </span><span style="color: #0000ff;">this</span>.logger.warn(<span style="color: #800000;">"</span><span style="color: #800000;">Exception encountered during context initialization - cancelling refresh attempt: </span><span style="color: #800000;">"</span> +<span style="color: #000000;"> var9);
            }

            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.destroyBeans();
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.cancelRefresh(var9);
            </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> var9;
        } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.resetCommonCaches();
        }

    }
}</span></pre>
复制代码

6  抽象父类AbstractApplicationContext类的子类EmbeddedWebApplicationContext的onRefresh方法

复制代码
@Override
    protected void onRefresh() {
        super.onRefresh();
        try {
            createEmbeddedServletContainer();
        }
        catch (Throwable ex) {
            throw new ApplicationContextException("Unable to start embedded container",
                    ex);
        }
    }
复制代码

7  在createEmbeddedServletContainer放啊发中会获取嵌入式Servlet容器工厂,由容器工厂创建Servlet

复制代码
private void createEmbeddedServletContainer() {
        EmbeddedServletContainer localContainer = this.embeddedServletContainer;
        ServletContext localServletContext = getServletContext();
        if (localContainer == null && localServletContext == null) {
                //获取嵌入式Servlet容器工厂 EmbeddedServletContainerFactory containerFactory
= getEmbeddedServletContainerFactory();
          //根据容器工厂获取对应嵌入式Servlet容器
this.embeddedServletContainer = containerFactory .getEmbeddedServletContainer(getSelfInitializer()); } else if (localServletContext != null) { try { getSelfInitializer().onStartup(localServletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } initPropertySources(); }
复制代码

8  从IOC容器中获取Servlet容器工厂

复制代码
//EmbeddedWebApplicationContext#getEmbeddedServletContainerFactory  
protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() {  
    // Use bean names so that we don't consider the hierarchy  
    String[] beanNames = getBeanFactory()  
        .getBeanNamesForType(EmbeddedServletContainerFactory.class);  
    if (beanNames.length == 0) {  
        throw new ApplicationContextException(  
            "Unable to start EmbeddedWebApplicationContext due to missing "  
            + "EmbeddedServletContainerFactory bean.");  
    }  
    if (beanNames.length > 1) {  
        throw new ApplicationContextException(  
            "Unable to start EmbeddedWebApplicationContext due to multiple "  
            + "EmbeddedServletContainerFactory beans : "  
            + StringUtils.arrayToCommaDelimitedString(beanNames));  
    }  
    return getBeanFactory().getBean(beanNames[0],  
                                    EmbeddedServletContainerFactory.class);  
}  
复制代码

9  使用Servlet容器工厂获取嵌入式Servlet容器,具体使用哪一个容器工厂看配置环境依赖

this.embeddedServletContainer = containerFactory  
            .getEmbeddedServletContainer(getSelfInitializer());  

10  上述创建过程  首先启动IOC容器,接着启动嵌入式Servlet容器,接着将IOC容器中剩下没有创建的对象获取出来,比如自己创建的controller

// Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);
复制代码
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // Initialize conversion service for this context.
        if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
                beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
            beanFactory.setConversionService(
                    beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
        }
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Register a default embedded value resolver if no bean post-processor
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> (such as a PropertyPlaceholderConfigurer bean) registered any before:
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> at this point, primarily for resolution in annotation attribute values.</span>
    <span style="color: #0000ff;">if</span> (!<span style="color: #000000;">beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> StringValueResolver() {
            @Override
            </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String resolveStringValue(String strVal) {
                </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> getEnvironment().resolvePlaceholders(strVal);
            }
        });
    }

    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.</span>
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.<span style="color: #0000ff;">class</span>, <span style="color: #0000ff;">false</span>, <span style="color: #0000ff;">false</span><span style="color: #000000;">);
    </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Stop using the temporary ClassLoader for type matching.</span>
    beanFactory.setTempClassLoader(<span style="color: #0000ff;">null</span><span style="color: #000000;">);

    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Allow for caching all bean definition metadata, not expecting further changes.</span>

beanFactory.freezeConfiguration();

    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Instantiate all remaining (non-lazy-init) singletons.</span>

beanFactory.preInstantiateSingletons();
}

复制代码

看看 preInstantiateSingletons方法

复制代码
public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }
    List</span>&lt;String&gt; beanNames = <span style="color: #0000ff;">new</span> ArrayList(<span style="color: #0000ff;">this</span><span style="color: #000000;">.beanDefinitionNames);
    Iterator var2 </span>=<span style="color: #000000;"> beanNames.iterator();

    </span><span style="color: #0000ff;">while</span>(<span style="color: #0000ff;">true</span><span style="color: #000000;">) {
        </span><span style="color: #0000ff;">while</span>(<span style="color: #0000ff;">true</span><span style="color: #000000;">) {
            String beanName;
            RootBeanDefinition bd;
            </span><span style="color: #0000ff;">do</span><span style="color: #000000;"> {
                </span><span style="color: #0000ff;">do</span><span style="color: #000000;"> {
                    </span><span style="color: #0000ff;">do</span><span style="color: #000000;"> {
                        </span><span style="color: #0000ff;">if</span> (!<span style="color: #000000;">var2.hasNext()) {
                            var2 </span>=<span style="color: #000000;"> beanNames.iterator();

                            </span><span style="color: #0000ff;">while</span><span style="color: #000000;">(var2.hasNext()) {
                                beanName </span>=<span style="color: #000000;"> (String)var2.next();
                                Object singletonInstance </span>= <span style="color: #0000ff;">this</span><span style="color: #000000;">.getSingleton(beanName);
                                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (singletonInstance instanceof SmartInitializingSingleton) {
                                    final SmartInitializingSingleton smartSingleton </span>=<span style="color: #000000;"> (SmartInitializingSingleton)singletonInstance;
                                    </span><span style="color: #0000ff;">if</span> (System.getSecurityManager() != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
                                        AccessController.doPrivileged(</span><span style="color: #0000ff;">new</span> PrivilegedAction&lt;Object&gt;<span style="color: #000000;">() {
                                            </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Object run() {
                                                smartSingleton.afterSingletonsInstantiated();
                                                </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;
                                            }
                                        }, </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.getAccessControlContext());
                                    } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
                                        smartSingleton.afterSingletonsInstantiated();
                                    }
                                }
                            }

                            </span><span style="color: #0000ff;">return</span><span style="color: #000000;">;
                        }

                        beanName </span>=<span style="color: #000000;"> (String)var2.next();
                        bd </span>= <span style="color: #0000ff;">this</span><span style="color: #000000;">.getMergedLocalBeanDefinition(beanName);
                    } </span><span style="color: #0000ff;">while</span><span style="color: #000000;">(bd.isAbstract());
                } </span><span style="color: #0000ff;">while</span>(!<span style="color: #000000;">bd.isSingleton());
            } </span><span style="color: #0000ff;">while</span><span style="color: #000000;">(bd.isLazyInit());

            </span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">this</span><span style="color: #000000;">.isFactoryBean(beanName)) {
                final FactoryBean</span>&lt;?&gt; factory = (FactoryBean)<span style="color: #0000ff;">this</span>.getBean(<span style="color: #800000;">"</span><span style="color: #800000;">&amp;</span><span style="color: #800000;">"</span> +<span style="color: #000000;"> beanName);
                boolean isEagerInit;
                </span><span style="color: #0000ff;">if</span> (System.getSecurityManager() != <span style="color: #0000ff;">null</span> &amp;&amp;<span style="color: #000000;"> factory instanceof SmartFactoryBean) {
                    isEagerInit </span>= ((Boolean)AccessController.doPrivileged(<span style="color: #0000ff;">new</span> PrivilegedAction&lt;Boolean&gt;<span style="color: #000000;">() {
                        </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Boolean run() {
                            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ((SmartFactoryBean)factory).isEagerInit();
                        }
                    }, </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.getAccessControlContext())).booleanValue();
                } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
                    isEagerInit </span>= factory instanceof SmartFactoryBean &amp;&amp;<span style="color: #000000;"> ((SmartFactoryBean)factory).isEagerInit();
                }

                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (isEagerInit) {
                    </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.getBean(beanName);
                }
            } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {<br>            //注册bean
                </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.getBean(beanName);
            }
        }
    }
}</span></pre>
复制代码

是使用getBean方法来通过反射将所有未创建的实例创建出来

  使用嵌入式Servlet容器:

     优点:   简单,便携

     缺点:   默认不支持jsp,优化定制比较复杂

使用外置Servlet容器的步骤:

  1  必须创建war项目,需要剑豪web项目的目录结构

  2  嵌入式Tomcat依赖scope指定provided

  3  编写SpringBootServletInitializer类子类,并重写configure方法

复制代码
public class ServletInitializer extends SpringBootServletInitializer {  
@Override  
</span><span style="color: #0000ff;">protected</span><span style="color: #000000;"> SpringApplicationBuilder configure(SpringApplicationBuilder application) {  
    </span><span style="color: #0000ff;">return</span> application.sources(SpringBoot04WebJspApplication.<span style="color: #0000ff;">class</span><span style="color: #000000;">);  
}  

}

复制代码

       4  启动服务器

jar包和war包启动区别

    jar包:执行SpringBootApplication的run方法,启动IOC容器,然后创建嵌入式Servlet容器

 war包:  先是启动Servlet服务器,服务器启动Springboot应用(springBootServletInitizer),然后启动IOC容器

Servlet 3.0+规则

    1  服务器启动(web应用启动),会创建当前web应用里面所有jar包里面的ServletContainerlnitializer实例

     2 ServletContainerInitializer的实现放在jar包的META-INF/services文件夹下

   3  还可以使用@HandlesTypes注解,在应用启动的时候加载指定的类。

外部Tomcat流程以及原理

  ①  启动Tomcat

  ②  根据上述描述的Servlet3.0+规则,可以在Spring的web模块里面找到有个文件名为javax.servlet.ServletContainerInitializer的文件,而文件的内容为org.springframework.web.SpringServletContainerInitializer,用于加载SpringServletContainerInitializer类

  ③看看SpringServletContainerInitializer定义

复制代码
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
</span><span style="color: #008000;">/*</span><span style="color: #008000;">*
 * Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}
 * implementations present on the application classpath.
 * &lt;p&gt;Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},
 * Servlet 3.0+ containers will automatically scan the classpath for implementations
 * of Spring's {@code WebApplicationInitializer} interface and provide the set of all
 * such types to the {@code webAppInitializerClasses} parameter of this method.
 * &lt;p&gt;If no {@code WebApplicationInitializer} implementations are found on the classpath,
 * this method is effectively a no-op. An INFO-level log message will be issued notifying
 * the user that the {@code ServletContainerInitializer} has indeed been invoked but that
 * no {@code WebApplicationInitializer} implementations were found.
 * &lt;p&gt;Assuming that one or more {@code WebApplicationInitializer} types are detected,
 * they will be instantiated (and &lt;em&gt;sorted&lt;/em&gt; if the @{@link
 * org.springframework.core.annotation.Order @Order} annotation is present or
 * the {@link org.springframework.core.Ordered Ordered} interface has been
 * implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)}
 * method will be invoked on each instance, delegating the {@code ServletContext} such
 * that each instance may register and configure servlets such as Spring's
 * {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener},
 * or any other Servlet API componentry such as filters.
 * @param webAppInitializerClasses all implementations of
 * {@link WebApplicationInitializer} found on the application classpath
 * @param servletContext the servlet context to be initialized
 * @see WebApplicationInitializer#onStartup(ServletContext)
 * @see AnnotationAwareOrderComparator
 </span><span style="color: #008000;">*/</span><span style="color: #000000;">
@Override
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> onStartup(Set&lt;Class&lt;?&gt;&gt;<span style="color: #000000;"> webAppInitializerClasses, ServletContext servletContext)
        throws ServletException {

    List</span>&lt;WebApplicationInitializer&gt; initializers = <span style="color: #0000ff;">new</span> LinkedList&lt;WebApplicationInitializer&gt;<span style="color: #000000;">();

    </span><span style="color: #0000ff;">if</span> (webAppInitializerClasses != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
        </span><span style="color: #0000ff;">for</span> (Class&lt;?&gt;<span style="color: #000000;"> waiClass : webAppInitializerClasses) {
            </span><span style="color: #008000;">//</span><span style="color: #008000;"> Be defensive: Some servlet containers provide us with invalid classes,
            </span><span style="color: #008000;">//</span><span style="color: #008000;"> no matter what @HandlesTypes says...</span>
            <span style="color: #0000ff;">if</span> (!waiClass.isInterface() &amp;&amp; !Modifier.isAbstract(waiClass.getModifiers()) &amp;&amp;<span style="color: #000000;">
                    WebApplicationInitializer.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">.isAssignableFrom(waiClass)) {
                </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {<br>                //为所有的WebApplicationInitializer类型创建实例,并加入集合中
                    initializers.add((WebApplicationInitializer) waiClass.newInstance());
                }
                </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Throwable ex) {
                    </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> ServletException(<span style="color: #800000;">"</span><span style="color: #800000;">Failed to instantiate WebApplicationInitializer class</span><span style="color: #800000;">"</span><span style="color: #000000;">, ex);
                }
            }
        }
    }

    </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (initializers.isEmpty()) {
        servletContext.log(</span><span style="color: #800000;">"</span><span style="color: #800000;">No Spring WebApplicationInitializer types detected on classpath</span><span style="color: #800000;">"</span><span style="color: #000000;">);
        </span><span style="color: #0000ff;">return</span><span style="color: #000000;">;
    }

    servletContext.log(initializers.size() </span>+ <span style="color: #800000;">"</span><span style="color: #800000;"> Spring WebApplicationInitializers detected on classpath</span><span style="color: #800000;">"</span><span style="color: #000000;">);
    AnnotationAwareOrderComparator.sort(initializers);<br>      //调用每一个WebApplicationInitializer实例的onstartup方法
    </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> (WebApplicationInitializer initializer : initializers) {
        initializer.onStartup(servletContext);
    }
}

}

复制代码

 在上面一段长长的注释中可以看到,SpringServletContainerInitializer将@HandlesTypes(WebApplicationInitializer.class)标注的所有WebApplicationInitializer这个类型的类都传入到onStartup方法的Set参数中,并通过反射为这些WebApplicationInitializer类型的类创建实例;

  ④  方法最后,每一个WebApplicationInitilizer实现调用自己onstartup方法

  ⑤  而WebApplicationInitializer有个抽象实现类SpringBootServletInitializer(记住我们继承了该抽象类),则会调用每一个WebApplicationInitializer实例(包括SpringBootServletInitializer)的onStartup方法:

复制代码
public abstract class SpringBootServletInitializer implements WebApplicationInitializer {  
</span><span style="color: #008000;">//</span><span style="color: #008000;">other code...  </span>
@Override public void onStartup(ServletContext servletContext) throws ServletException { // Logger initialization is deferred in case a ordered // LogServletContextInitializer is being used this.logger = LogFactory.getLog(getClass()); //创建IOC容器 WebApplicationContext rootAppContext = createRootApplicationContext( servletContext); if (rootAppContext != null) { servletContext.addListener(new ContextLoaderListener(rootAppContext) { @Override public void contextInitialized(ServletContextEvent event) { // no-op because the application context is already initialized } }); } else { this.logger.debug("No ContextLoaderListener registered, as " + "createRootApplicationContext() did not " + "return an application context"); } }
</span><span style="color: #0000ff;">protected</span><span style="color: #000000;"> WebApplicationContext createRootApplicationContext(  
        ServletContext servletContext) {  
    </span><span style="color: #008000;">//</span><span style="color: #008000;">创建Spring应用构建器,并进行相关属性设置  </span>
    SpringApplicationBuilder builder =<span style="color: #000000;"> createSpringApplicationBuilder();  
    StandardServletEnvironment environment </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> StandardServletEnvironment();  
    environment.initPropertySources(servletContext, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);  
    builder.environment(environment);  
    builder.main(getClass());  
    ApplicationContext parent </span>=<span style="color: #000000;"> getExistingRootWebApplicationContext(servletContext);  
    </span><span style="color: #0000ff;">if</span> (parent != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {  
        </span><span style="color: #0000ff;">this</span>.logger.info(<span style="color: #800000;">"</span><span style="color: #800000;">Root context already created (using as parent).</span><span style="color: #800000;">"</span><span style="color: #000000;">);  
        servletContext.setAttribute(  
                WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);  
        builder.initializers(</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> ParentContextApplicationContextInitializer(parent));  
    }  
    builder.initializers(  
            </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> ServletContextApplicationContextInitializer(servletContext));  
    builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">);  
      
    </span><span style="color: #008000;">//</span><span style="color: #008000;">调用configure方法,创建war类型的web项目后,由于编写SpringBootServletInitializer的子类重写configure方法,所以此处调用的是我们定义的子类重写的configure方法  </span>
    builder =<span style="color: #000000;"> configure(builder);  
      
    </span><span style="color: #008000;">//</span><span style="color: #008000;">通过构建器构建了一个Spring应用  </span>
    SpringApplication application =<span style="color: #000000;"> builder.build();  
    </span><span style="color: #0000ff;">if</span> (application.getSources().isEmpty() &amp;&amp;<span style="color: #000000;"> AnnotationUtils  
            .findAnnotation(getClass(), Configuration.</span><span style="color: #0000ff;">class</span>) != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {  
        application.getSources().add(getClass());  
    }  
    Assert.state(</span>!<span style="color: #000000;">application.getSources().isEmpty(),  
            </span><span style="color: #800000;">"</span><span style="color: #800000;">No SpringApplication sources have been defined. Either override the </span><span style="color: #800000;">"</span>  
                    + <span style="color: #800000;">"</span><span style="color: #800000;">configure method or add an @Configuration annotation</span><span style="color: #800000;">"</span><span style="color: #000000;">);  
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Ensure error pages are registered  </span>
    <span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">this</span><span style="color: #000000;">.registerErrorPageFilter) {  
        application.getSources().add(ErrorPageFilterConfiguration.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">);  
    }  
    </span><span style="color: #008000;">//</span><span style="color: #008000;">启动Spring应用  </span>
    <span style="color: #0000ff;">return</span><span style="color: #000000;"> run(application);  
}  
  
</span><span style="color: #008000;">//</span><span style="color: #008000;">Spring应用启动,创建并返回IOC容器  </span>
<span style="color: #0000ff;">protected</span><span style="color: #000000;"> WebApplicationContext run(SpringApplication application) {  
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> (WebApplicationContext) application.run();  
}  

}

复制代码

   SpringBootServletInitializer实例执行onStartup方法的时候会通过createRootApplicationContext方法来执行run方法,接下来的过程就同以jar包形式启动的应用的run过程一样了,在内部会创建IOC容器并返回,只是以war包形式的应用在创建IOC容器过程中,不再创建Servlet容器了。

原文地址:http://www.cnblogs.com/developerxiaofeng/p/9081689.html
原文地址:https://www.cnblogs.com/jpfss/p/10039120.html