項目啓動之spring篇

在之前終於是把項目跑起來了,也是踩了不少的坑,把bug還原了一遍又一遍,希望能看的更清楚。現在我們跳過tomcat再來看看spring是如何啓動的。


                   項目啓動過程之spring篇

1.創建WebApplicationContext

# 首先我們在web.xml的配置了這麼一個lisenner

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

# 從源碼中找到該類,類中的方法都是調用父類來實現的,如此明顯的裝飾者模式。

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

    .....

}

# 再看看ContextLoader這個類

public class ContextLoader {


   # 這個靜態方法只爲加載一個ContextLoader.properties文件,不出所料的這個文件跟類在同一個文件夾下。

   # 文件中只有一句話 -> org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

   static {

        try {

            ClassPathResource resource = new ClassPathResource("ContextLoader.properties", ContextLoader.class);

            defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);

        } catch (IOException var1) {

            throw new IllegalStateException("Could not load 'ContextLoader.properties': " + var1.getMessage());

        }

        currentContextPerThread = new ConcurrentHashMap(1);

    }

    # 這個方法大致就是如果web.xml沒有配置特殊的contextClass則會使用defaultStrategies中指定的類,也就是上面靜態方法加載到的配置 XmlWebApplicationContext

    protected Class<?> determineContextClass(ServletContext servletContext) {

        String contextClassName = servletContext.getInitParameter("contextClass");

        if (contextClassName != null) {

            try {

                return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());

            } catch (ClassNotFoundException var4) {

                throw new ApplicationContextException("Failed to load custom context class [" + contextClassName + "]", var4);

            }

        } else {

            # 如果在web.xml中並未指定contextClass

            # 簡單寫成: contextClassName = "org.springframework.web.context.support.XmlWebApplicationContext"

            contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());


            try {

                return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());

            } catch (ClassNotFoundException var5) {

                throw new ApplicationContextException("Failed to load default context class [" + contextClassName + "]", var5);

            }

        }

    }

    protected WebApplicationContext createWebApplicationContext(ServletContext sc) {

       # 將裏面代碼簡單寫成:

       # return (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(this.determineContextClass(sc));

    }

    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {

        if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {

           ....

        } else {

            .....

            # 此時就要開始創建 WebApplicationContext 了

            try {

                if (this.context == null) {

                    # 我們假定 this.context 的類型就是 XmlWebApplicationContext

                    this.context = this.createWebApplicationContext(servletContext);

                }


                if (this.context instanceof ConfigurableWebApplicationContext) {

                    ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)this.context;

                    

                    if (!cwac.isActive()) {   # 剛跑起的項目context一般都沒被激活

                        if (cwac.getParent() == null) {

                            # 很奇怪,loadParentContext返回的是  return null  ??

                            ApplicationContext parent = this.loadParentContext(servletContext);

                            cwac.setParent(parent);

                        }

                        # 這個方法主要是設置contextId,若沒有在web.xml中指定,則會像這個樣子:

                        #   org.springframework.web.context.WebApplicationContext:${contextPath}

                        this.configureAndRefreshWebApplicationContext(cwac, servletContext);

                    }

                }

                # 這個纔是Lisener的關鍵,把創建的WebApplicationContext加入到servletContext中。 

                servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

                ClassLoader ccl = Thread.currentThread().getContextClassLoader();

                if (ccl == ContextLoader.class.getClassLoader()) {

                    currentContext = this.context;

                } else if (ccl != null) {

                    currentContextPerThread.put(ccl, this.context);

                }

                return this.context;

            .....

        }

    }


}

# 在XWAC中提供了默認的配置文件位置

public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {

    public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

    public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";

    public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";


    .....

}



小結一下:   tomcat啓動時會給配置在web.xml中指定的lisener傳遞一個事件,讓其初始化創建一個WebApplicationContext對象,並將其加入到ServletContext中。而在spring-web中ContextLoaderListener類爲我們提供使用默認或自定義兩種生成WebApplicationContext對象,需要使用自定義則需要在web.xml中指定contextClass屬性,並且創建對應的類。創建好了context之後,下一步便是加載applicationContext中的bean了,暫時也還沒有發現如何發起加載bean的過程,繼續學習吧。。。



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