• 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
  • 相关阅读:
    CSS3实现的超酷页面过渡效果
    HTML5基本知识小测验
    多线程揭秘
    【框架设计】泛型的应用
    sql server 2005中的except和INTERSECT运算 .
    C#应用MemoryStream提高File读取速度
    .net错误处理机制
    sql 权限导致的问题
    超时时间已到。在操作完成之前超时时间已过或服务器未响应
    SQL差集的使用(EXCEPT)
  • 原文地址:https://www.cnblogs.com/jpfss/p/10039120.html
Copyright © 2020-2023  润新知