類的繼承關係
Spring MVC前端控制器DispatcherServlet
-->FrameworkServlet
-->HttpServletBean
-->HttpServlet
前端
HttpServlet是Servlet規範中的核心類,實現Servlet接口,繼承此類用於處理用戶請求。web
HttpServletBean主要配置servlet中初始化參數。繼承HttpServlet,並實現無參的init()方法,用於設置在web.xml中配置的contextConfigLocation屬性,此屬性指定Spring MVC的配置文件地址,默認爲WEB-INF/[servlet-name]-servlet.xml,源碼以下:spring
/** * DispatcherServlet第一次加載時調用init方法 */ @Override public final void init() throws ServletException { // 省略日誌... // 獲取在web.xml配置的初始化參數<init-param>,並將其設置到DispatcherServlet中 PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); if (!pvs.isEmpty()) { try { BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); initBeanWrapper(bw); bw.setPropertyValues(pvs, true); } catch (BeansException ex) { if (logger.isErrorEnabled()) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); } throw ex; } } // 調用子類(FrameworkServlet)進行初始化 // 模版方法,此方法在HttpServletBean自己是空的,可是由於調用方法的對象是DispatcherServlet // 因此優先在DispatcherServlet找,找不到再去父類找,最後在FrameworkServlet找到 initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet '" + getServletName() + "' configured successfully"); } }
總結HttpServletBean的做用:編程
FrameworkServlet主要建立WebApplicationContext上下文,重寫了HttpServletBean的initServletBean()方法。app
該方法只有兩句關鍵代碼,其做用一個是調用initWebApplicationContext()方法初始化WebApplicationContext上下文,另外一個是調用子類方法initFrameworkServlet()方法,源碼以下:ide
@Override protected final void initServletBean() throws ServletException { getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'"); // 省略日誌... long startTime = System.currentTimeMillis(); try { // 初始化WebApplicationContext,並調用子類(DispatcherServlet)的onRefresh(wac)方法 this.webApplicationContext = initWebApplicationContext(); initFrameworkServlet(); } catch (ServletException | RuntimeException ex) { this.logger.error("Context initialization failed", ex); throw ex; } if (this.logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " + elapsedTime + " ms"); } }
protected WebApplicationContext initWebApplicationContext() { // 獲取root WebApplicationContext,即web.xml中配置的listener(ContextLoaderListener) WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; // 判斷容器是否由編程式傳入(便是否已經存在了容器實例),存在的話直接賦值給wac,給springMVC容器設置父容器 // 最後調用刷新函數configureAndRefreshWebApplicationContext(wac),做用是把Spring MVC配置文件的配置信息加載到容器中去 if (this.webApplicationContext != null) { // context上下文在構造是注入 wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; if (!cwac.isActive()) { // context沒有被refreshed,提供一些諸如設置父context、設置應用context id等服務 if (cwac.getParent() == null) { cwac.setParent(rootContext); } configureAndRefreshWebApplicationContext(cwac); } } } // 在ServletContext中尋找是否有Spring MVC容器,初次運行是沒有的,Spring MVC初始化完畢ServletContext就有了Spring MVC容器 if (wac == null) { wac = findWebApplicationContext(); } // 當wac既沒有沒被編程式註冊到容器中的,也沒在ServletContext找獲得,此時就要新建一個Spring MVC容器 if (wac == null) { // 若是沒有WebApplicationContext則建立 wac = createWebApplicationContext(rootContext); } // 到這裏Spring MVC容器已經建立完畢,接着真正調用DispatcherServlet的初始化方法onRefresh(wac) // 此處還是模板模式的應用 if (!this.refreshEventReceived) { onRefresh(wac); } // 將Spring MVC容器存放到ServletContext中去,方便下次取出來 if (this.publishContext) { // Publish the context as a servlet context attribute. String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); if (this.logger.isDebugEnabled()) { this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() + "' as ServletContext attribute with name [" + attrName + "]"); } } return wac; }
protected WebApplicationContext createWebApplicationContext(@Nullable WebApplicationContext parent) { return createWebApplicationContext((ApplicationContext) parent); } protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) { Class<?> contextClass = getContextClass(); if (this.logger.isDebugEnabled()) { this.logger.debug("Servlet with name '" + getServletName() + "' will try to create custom WebApplicationContext context of class '" + contextClass.getName() + "'" + ", using parent context [" + parent + "]"); } if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException( "Fatal initialization error in servlet with name '" + getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext"); } // 實例化容器 ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); // 設置容器環境 wac.setEnvironment(getEnvironment()); // 設置父容器 wac.setParent(parent); // 加載Spring MVC的配置信息,如:bean注入、註解、掃描等等 String configLocation = getContextConfigLocation(); if (configLocation != null) { wac.setConfigLocation(configLocation); } // 刷新容器,根據Spring MVC配置文件完成初始化操做 configureAndRefreshWebApplicationContext(wac); return wac; }
總結FrameworkServlet的做用:函數
DispatcherServlet是Spring MVC核心,它是J2EE規範前端控制器的實現,負責攔截用戶請求,並解析請求進行轉發。學習
@Override protected void onRefresh(ApplicationContext context) { initStrategies(context); } protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); // 文件上傳解析 initLocaleResolver(context); // 本地解析 initThemeResolver(context); //主題解析 initHandlerMappings(context); // URL請求映射 initHandlerAdapters(context); // 初始化Controller類 initHandlerExceptionResolvers(context); // 異常解析 initRequestToViewNameTranslator(context); initViewResolvers(context); // 視圖解析 initFlashMapManager(context); }
最後建立了qq羣方便你們交流,可掃描加入,同時也可加我qq:276420284,共同窗習、共同進步,謝謝!ui