Spring源碼解析-Web容器啓動過程

  Web容器啓動過程,主要講解Servlet和Spring容器結合的內容。

  流程圖如下:

  

  Web容器啓動的Root Context是有ContextLoaderListener,一般使用spring,都會在web.xml中配置這個監聽器。

<listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

  下面就從這裏入手,看看它是如何啓動spring容器。

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

    
    public ContextLoaderListener(WebApplicationContext context) {
        super(context);
    }


    /**
     * Initialize the root web application context.
     */
    @Override
    public void contextInitialized(ServletContextEvent event) {
        initWebApplicationContext(event.getServletContext());
    }


    /**
     * Close the root web application context.
     */
    @Override
    public void contextDestroyed(ServletContextEvent event) {
        closeWebApplicationContext(event.getServletContext());
        ContextCleanupListener.cleanupAttributes(event.getServletContext());
    }

}

這個類繼承了ContextLoader,同時實現了ServletContextListener,從註釋上可以看出,web應用會調用contextInitalized方法進行初始化。

先看一下ServletContextListener.

public interface ServletContextListener extends EventListener {
    void contextInitialized(ServletContextEvent var1);

    void contextDestroyed(ServletContextEvent var1);
}

從名字可以看出,一個是初始化方法,另一個是銷燬是調用的方法。

回到上面而initWebApplicationContext方法,通過createWebApplicationContext方法獲取WebApplicationContext,調用determineContextClass方法如下:

/**
     * Return the WebApplicationContext implementation class to use, either the
     * default XmlWebApplicationContext or a custom context class if specified.
     * @param servletContext current servlet context
     * @return the WebApplicationContext implementation class to use
     * @see #CONTEXT_CLASS_PARAM
     * @see org.springframework.web.context.support.XmlWebApplicationContext
     */
    protected Class<?> determineContextClass(ServletContext servletContext) {
        String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
        if (contextClassName != null) {
            try {
                return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
            }
            catch (ClassNotFoundException ex) {
                throw new ApplicationContextException(
                        "Failed to load custom context class [" + contextClassName + "]", ex);
            }
        }
        else {
            contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
            try {
                return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
            }
            catch (ClassNotFoundException ex) {
                throw new ApplicationContextException(
                        "Failed to load default context class [" + contextClassName + "]", ex);
            }
        }
    }

從註釋上可以看出返回的是XmlWebApplicationContext。

回到initWebApplicationContext方法中,有一段

if (this.context instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
                if (!cwac.isActive()) {
                    // The context has not yet been refreshed -> provide services such as
                    // setting the parent context, setting the application context id, etc
                    if (cwac.getParent() == null) {
                        // The context instance was injected without an explicit parent ->
                        // determine parent for root web application context, if any.
                        ApplicationContext parent = loadParentContext(servletContext);
                        cwac.setParent(parent);
                    }
                    configureAndRefreshWebApplicationContext(cwac, servletContext);
                }
            }

會調用configureAndRefreshWebApplication方法,感覺是配置和刷新,進入方法。

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
        if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
            // The application context id is still set to its original default value
            // -> assign a more useful id based on available information
            String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
            if (idParam != null) {
                wac.setId(idParam);
            }
            else {
                // Generate default id...
                wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                        ObjectUtils.getDisplayString(sc.getContextPath()));
            }
        }
        
        wac.setServletContext(sc);
//獲取配置的參數信息 String configLocationParam
= sc.getInitParameter(CONFIG_LOCATION_PARAM); if (configLocationParam != null) { wac.setConfigLocation(configLocationParam); } // The wac environment's #initPropertySources will be called in any case when the context // is refreshed; do it eagerly here to ensure servlet property sources are in place for // use in any post-processing or initialization that occurs below prior to #refresh ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(sc, null); } customizeContext(sc, wac);
//刷新上下文-->AbsreactApplicationContext.refresh() wac.refresh(); }

至此,通過wac.refresh()啓動Spring容器。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章