Web 应用中使用的容器是 XmlWebApplicationContext ,其类图如下,可以看出最终是一个实现了 BeanFactory 的类
IOC容器源码的入口
我们知道 Spring 框架不仅仅是面向 Web 应用,所以 Spring 中对应不同场景有许多 IOC 容器的实现类,其中有简单的也有复杂的,在此我们跳过简单容器的讲解,直接以我们最熟悉、也是最感兴趣的 Java Web 项目下手,寻找其对应的 IOC 容器实现类,同时一口气寻找到 IOC 容器的关键入口方法 refresh() 。
public WebApplicationContext initWebApplicationContext(ServletContext servletContext){ . . . try { // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. if (this.context == null) { /** [note-by-leapmie] 获取SpringIOC容器类型 **/ this.context = createWebApplicationContext(servletContext); } 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); } /** [note-by-leapmie] 配置和刷新容器 **/ configureAndRefreshWebApplicationContext(cwac, servletContext); } } . . . }
protectedvoidconfigureAndRefreshWebApplicationContext(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())); } }
// 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); }
// Destroy already created singletons to avoid dangling resources. destroyBeans();
// Reset 'active' flag. cancelRefresh(ex);
// Propagate exception to caller. throw ex; }
finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
至此我们已经找到了关键的入口 refresh() ,我们看一下在调用过程图中我们所处的位置
refresh 方法是 Spring IOC 容器启动过程的核心方法,方法中按顺序调用了好几个命名清晰的方法,其对应的都是 IOC 容器启动过程的关键步骤,更多的细节我们将在下一节继续讲解。