Spring 系列目录(http://www.javashuo.com/article/p-kqecupyl-bm.html)html
《Servlet 2.x 规范》:http://www.javashuo.com/article/p-dggyaqqw-dn.htmljava
Servlet 容器在启动时会调用 ServletContextListener 的 contextInitialized() 方法。同时 Servlet 在初始化时会执行 init 方法。Spring MVC 正是在这两个过程当中建立 Root WebApplicationContext 和 Servlet WebApplicationContext 容器。web
ContextLoaderListener 的 contextInitialized 只是简单的调用了一个其父类 ContextLoader 的 initWebApplicationContext 方法,建立了一个 Root 容器。spring
// 建立 Root WebApplicationContext public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { throw new IllegalStateException( "Cannot initialize context because there is already a root application context present"); } try { // 1. 建立 Root WebApplicationContext if (this.context == null) { this.context = createWebApplicationContext(servletContext); } // 2. 配置 Root WebApplicationContext if (this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; if (!cwac.isActive()) { if (cwac.getParent() == null) { ApplicationContext parent = loadParentContext(servletContext); cwac.setParent(parent); } configureAndRefreshWebApplicationContext(cwac, servletContext); } } servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); // 3. 保存 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; } catch (RuntimeException | Error ex) { } }
类继承关系:DispatcherServlet -> FrameworkServlet -> HttpServletBean -> HttpServlet -> Servlet
初始化 DispatcherServlet 时会调用 Servlet 的 init() 方法。spring-mvc
// HttpServletBean#init @Override public final void init() throws ServletException { // 省略... initServletBean(); } // FrameworkServlet#initServletBean @Override protected final void initServletBean() throws ServletException { this.webApplicationContext = initWebApplicationContext(); initFrameworkServlet(); }
至此终于看到 Servlet WebApplicationContext 的建立了。mvc
protected WebApplicationContext initWebApplicationContext() { // 1. 获取父容器 WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; // 2. 子容器已经存在则设置其父容器并启动 if (this.webApplicationContext != null) { wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; if (!cwac.isActive()) { if (cwac.getParent() == null) { cwac.setParent(rootContext); } configureAndRefreshWebApplicationContext(cwac); } } } // 3. 不存在则建立一个新子容器 if (wac == null) { wac = findWebApplicationContext(); } if (wac == null) { wac = createWebApplicationContext(rootContext); } if (!this.refreshEventReceived) { onRefresh(wac); } if (this.publishContext) { String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); } return wac; }
天天用心记录一点点。内容也许不重要,但习惯很重要!app