摘要:核心類類的繼承關系前端控制器是規范中的核心類,實現接口,繼承此類用于處理用戶請求。主要配置中初始化參數。
Spring MVC 核心類
類的繼承關系
Spring MVC前端控制器DispatcherServlet-->FrameworkServlet-->HttpServletBean-->HttpServlet
HttpServlet是Servlet規范中的核心類,實現Servlet接口,繼承此類用于處理用戶請求。
HttpServletBeanHttpServletBean主要配置servlet中初始化參數。繼承HttpServlet,并實現無參的init()方法,用于設置在web.xml中配置的contextConfigLocation屬性,此屬性指定Spring MVC的配置文件地址,默認為WEB-INF/[servlet-name]-servlet.xml,源碼如下:
/** * DispatcherServlet第一次加載時調用init方法 */ @Override public final void init() throws ServletException { // 省略日志... // 獲取在web.xml配置的初始化參數,并將其設置到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的作用:
獲取web.xml的中配置DispatcherServlet的初始化參數,存放到一個參數容器ServletConfigPropertyValues中
根據傳進來的this創建BeanWrapper,本質上它就是DispatcherServlet
通過bw.setPropertyValues(pvs, true),把參數設置到bw(即DispatcherServlet)里面去
最后調用子類的initServletBean()
FrameworkServletFrameworkServlet主要創建WebApplicationContext上下文,重寫了HttpServletBean的initServletBean()方法。
1、initServletBean該方法只有兩句關鍵代碼,其作用一個是調用initWebApplicationContext()方法初始化WebApplicationContext上下文,另一個是調用子類方法initFrameworkServlet()方法,源碼如下:
@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"); } }2、initWebApplicationContext
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; }3、createWebApplicationContext
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的作用:
創建Spring MVC的容器,根據配置文件實例化里面各種bean,并將之與spring的容器進行關聯
把創建出來的Spring MVC容器存放到ServletContext中
通過模板方法模式調用子類DispatcherServlet的onRefresh()方法
DispatcherServletDispatcherServlet是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); }總結
容器啟動時,加載web.xml部署描述文件,掃描到并找到DispatcherServlet核心控制器
調用HttpServletBean的init()方法,把DispatcherServlet初始化參數設置到DispatcherServlet中,并調用子類FrameworkServlet的initServletBean()方法
FrameworkServlet的initServletBean()創建Spring MVC容器并初始化,并且和Spring父容器進行關聯,使得Spring MVC容器能訪問Spring容器中定義的bean,之后調用子類DispatcherServlet的onRefresh()方法
DispatcherServlet的onRefresh(ApplicationContext context)對DispatcherServlet的策略組件進行初始化
最后創建了qq群方便大家交流,可掃描加入,同時也可加我qq:276420284,共同學習、共同進步,謝謝!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69261.html
摘要:接口接口作用是將請求映射到處理程序,以及預處理和處理后的攔截器列表,映射是基于一些標準的,其中的細節因不同的實現而不相同。該參數是類型,作用是檢查所有的映射解析器或使用或為的,默認為,即從上下文中檢查所有的。 概述 在Spring MVC啟動章節https://segmentfault.com/a/1190000014674239,介紹到了DispatcherServlet的onRef...
摘要:概述本章我們主要分析處理組件的處理流程以及其接口源碼。概括來說,使用組件分為兩步,首先是注冊組件,其次是處理用戶請求,以下針對這兩個過程進行詳細的分析。本系列文章是基于。接下來的幾章將分析提供的適配策略,希望本節對大家能有幫助,謝謝。 概述 本章我們主要分析Spring處理HandlerAdapter組件的處理流程以及其接口源碼。概括來說,Spring使用HandlerAdapter組...
摘要:與類圖對比,類繼承自抽象類,其又繼承自抽象類,再往上繼承關系與一致。創建初始化上一章我們分析了的創建初始化過程,的創建初始化過程與一樣,方法的入口在抽象類中的方法。至此,代碼編寫完畢。 概述 本節我們繼續分析HandlerMapping另一個實現類BeanNameUrlHandlerMapping,從類的名字可知,該類會根據請求的url與spring容器中定義的bean的name屬性值...
摘要:需求根據客戶端環境,界面顯示不同的國旗圖案。選擇的技術方案可利用提供的國際化和主題定制來解決。注意此時返回的中沒有國際化及主題相關的信息。修改請求參數的值為荷蘭,即后再發起請求,結果如下與預期一致,測試通過。 概述 以上分析了Spring MVC的LocaleResolver和ThemeResolver兩個策略解析器,在實際項目中很少使用,尤其是ThemeResolver,花精力去分析...
摘要:由于抽象類重寫了父類的方法,所以此時會調用的方法,在該方法中通過調用父類的方法,該方法通過模板方法模式最終調到類的方法。分析該類間接實現了接口,直接實現該接口的是抽象類,映射與請求。 概述 在前一章https://segmentfault.com/a/1190000014901736的基礎上繼續分析,主要完成SimpleUrlHandlerMapping類的原理。 本系列文章是基于Sp...
閱讀 2025·2023-04-26 00:16
閱讀 3475·2021-11-15 11:38
閱讀 3168·2019-08-30 12:50
閱讀 3178·2019-08-29 13:59
閱讀 750·2019-08-29 13:54
閱讀 2496·2019-08-29 13:42
閱讀 3305·2019-08-26 11:45
閱讀 2187·2019-08-26 11:36