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