SpringMVC中的DispatcherServlet初始化流程詳解
DispatcherServlet初始化流程
分析一下DispatcherServlet這個前端控制器的啟動和初始化的整個過程
通過前面分析已經知道了DispatcherServlet這個前端控制器是一個Servlet了,所以生命周期和普通的Servlet是差不多的,在一個Servlet初始化的時候都會調用該Servlet的init()方法。下面這個是DispatcherSerlvet父類HttpServletBean中的init方法。
我們發(fā)現(xiàn)這里會調用initServletBean()方法進行具體的初始化,而該類這個方法的具體實現(xiàn)這是其子類FrameworkServlet。主要邏輯就是初始化上下文。
protected final void initServletBean() throws ServletException { this.getServletContext().log("Initializing Spring " + this.getClass().getSimpleName() + " \'" + this.getServletName() + "\'"); if(this.logger.isInfoEnabled()) { this.logger.info("Initializing Servlet \'" + this.getServletName() + "\'"); } long startTime = System.currentTimeMillis(); try { /** 這里初始化上下文 **/ this.webApplicationContext = this.initWebApplicationContext(); this.initFrameworkServlet(); } catch (RuntimeException | ServletException var4) { this.logger.error("Context initialization failed", var4); throw var4; } if(this.logger.isDebugEnabled()) { String value = this.enableLoggingRequestDetails?"shown which may lead to unsafe logging of potentially sensitive data":"masked to prevent unsafe logging of potentially sensitive data"; this.logger.debug("enableLoggingRequestDetails=\'" + this.enableLoggingRequestDetails + "\': request parameters and headers will be " + value); } if(this.logger.isInfoEnabled()) { this.logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms"); } }
繼續(xù)跟進initWebApplicationContext這個方法
protected WebApplicationContext initWebApplicationContext() { /** 若webApplicationContext不為空的時候從SerlvetContext去出根上下文作為它的雙親上下文 **/ WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext()); WebApplicationContext wac = null; if(this.webApplicationContext != null) { wac = this.webApplicationContext; if(wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext attrName = (ConfigurableWebApplicationContext)wac; if(!attrName.isActive()) { if(attrName.getParent() == null) { attrName.setParent(rootContext); } this.configureAndRefreshWebApplicationContext(attrName); } } } if(wac == null) { wac = this.findWebApplicationContext(); } if(wac == null) { wac = this.createWebApplicationContext(rootContext); } //這里通過調用子類DispatcherServlet實現(xiàn)的onRefresh方法 if(!this.refreshEventReceived) { this.onRefresh(wac); } //把當前建立好的上下文存到ServletContext里面去 if(this.publishContext) { String attrName1 = this.getServletContextAttributeName(); this.getServletContext().setAttribute(attrName1, wac); } return wac; }
繼續(xù)跟進這個onRefresh方法,發(fā)現(xiàn)是一個模板方法,其具體實現(xiàn)子類則是DispatcherServlet。
跳轉到DispatcherServlet中查看該方法,發(fā)現(xiàn)里面又調用了initStrategies這個方法
這時我們就大致了解了,這個DispatcherServlet初始化的過程了,首先DispatcherServlet持有者一個以自己的Servlet名字命名的Ioc容器,也就是我們看到的WebApplicationContext對象,這個Ioc容器建立起來后,與Web容器相關的各種配置加載也都完成了。并且這個初始化的入口就是由最初的HttpServletBean的init方法觸發(fā)的,因為這個HttpServletBean是HttpServlet的子類,接下來HttpServletBean的子類FrameworkServlet對Ioc容器進行了初始化操作,并且利用onRefresh方法回調了DispatcherServlet中的initStrategies方法,在這個方法里啟動了整個SpringMVC框架了,我們繼續(xù)往下面跟進看看。
//該屬性默認為true private boolean detectAllHandlerMappings = true; private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; //這里面的邏輯是從導入所有的HandlerMappingBean,這些Bean有可能存在與雙親容器中,也可能在DispathcerServlet持有的容器的,這里detectAllHandlerMappings默認為true,默認從所有容器中導入 if(this.detectAllHandlerMappings) { Map hm = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if(!hm.isEmpty()) { this.handlerMappings = new ArrayList(hm.values()); AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { //否則通過直接通過名字從當前的IOC容器中通過getBean方法獲取handlerMapping try { HandlerMapping hm1 = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm1); } catch (NoSuchBeanDefinitionException var3) { ; } } //如果還是沒有找到hadlerMapping就需要設定默認的handlerMappings了 if(this.handlerMappings == null) { this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class); if(this.logger.isTraceEnabled()) { this.logger.trace("No HandlerMappings declared for servlet \'" + this.getServletName() + "\': using default strategies from DispatcherServlet.properties"); } } }
下面是用debugger看看它究竟獲取了那些handlerMapping,如下:7個handlerMapping
除了這個初始化handlerMapping的initHandlerMapping方法,當然還初始化了很多東西,如支持國際化的LocalResolver以及視圖生成的ViewResolver等的初始化過程,其余的有興趣自己跟著看一下,這里就不細跟了。到這里我們就知道了整個DispatcherServlet的初始化的大體流程了。
到此這篇關于SpringMVC中的DispatcherServlet初始化流程詳解的文章就介紹到這了,更多相關DispatcherServlet初始化流程內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot+EasyPoi實現(xiàn)excel導出功能
最新小編遇到這樣一個需求,根據檢索條件查詢列表并將結果導出到excel,實現(xiàn)過程也非常簡單,感興趣的朋友跟隨小編一起看看吧2021-09-09解決springboot 實體類String轉Date類型的坑
這篇文章主要介紹了解決springboot 實體類String轉Date類型的坑,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10SpringBoot實現(xiàn)在webapp下直接訪問html,jsp
這篇文章主要介紹了SpringBoot實現(xiàn)在webapp下直接訪問html,jsp問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10CMD運行Intellij Idea編譯后的class文件操作
這篇文章主要介紹了CMD運行Intellij Idea編譯后的class文件操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02SpringBoot Filter修改返回內容,解決請求卡死200的錯誤
這篇文章主要介紹了SpringBoot Filter修改返回內容,解決請求卡死200的錯誤問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07