javascript
Spring MVC 源码-初始化阶段
我們首先找到DispatcherServlet 這個類,必然是尋找init()方法。然后,我們發現其init方法其實在父類HttpServletBean 中,其源碼如下:
@Override public final void init() throws ServletException {if (logger.isDebugEnabled()) {logger.debug("Initializing servlet '" + getServletName() + "'");}// Set bean properties from init parameters.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;}}// Let subclasses do whatever initialization they like.initServletBean();if (logger.isDebugEnabled()) {logger.debug("Servlet '" + getServletName() + "' configured successfully");} }我們看到在這段代碼中, 又調用了一個重要的initServletBean() 方法。進入initServletBean()方法看到以下源碼:
protected final void initServletBean() throws ServletException {getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");if (this.logger.isInfoEnabled()) {this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");}long startTime = System.currentTimeMillis();try {this.webApplicationContext = initWebApplicationContext();initFrameworkServlet();}catch (ServletException ex) {this.logger.error("Context initialization failed", ex);throw ex;}catch (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");} }這段代碼中最主要的邏輯就是初始化IOC 容器,最終會調用refresh()方法,前面的章節中對IOC 容器的初始化細節我們已經詳細掌握,在此我們不再贅述。我們看到上面的代碼中,IOC 容器初始化之后,最后有調用了onRefresh()方法。這個方法最終是在DisptcherServlet 中實現,來看源碼:
@Override protected void onRefresh(ApplicationContext context) {initStrategies(context); } /*** Initialize the strategy objects that this servlet uses.* <p>May be overridden in subclasses in order to initialize further strategy objects.*/ //初始化策略 protected void initStrategies(ApplicationContext context) {//多文件上傳的組件initMultipartResolver(context);//初始化本地語言環境initLocaleResolver(context);//初始化模板處理器initThemeResolver(context);//handlerMappinginitHandlerMappings(context);//初始化參數適配器initHandlerAdapters(context);//初始化異常攔截器initHandlerExceptionResolvers(context);//初始化視圖預處理器initRequestToViewNameTranslator(context);//初始化視圖轉換器initViewResolvers(context);//initFlashMapManager(context); }到這一步就完成了Spring MVC 的九大組件的初始化。接下來,我們來看url 和Controller的關系是如何建立的呢? HandlerMapping 的子類AbstractDetectingUrlHandlerMapping 實現了initApplicationContext()方法,所以我們直接看子類中的初始化容器方法。
@Override public void initApplicationContext() throws ApplicationContextException {super.initApplicationContext();detectHandlers(); } /*** 建立當前ApplicationContext中的所有controller和url的對應關系*/ protected void detectHandlers() throws BeansException {ApplicationContext applicationContext = obtainApplicationContext();if (logger.isDebugEnabled()) {logger.debug("Looking for URL mappings in application context: " + applicationContext);}// 獲取ApplicationContext容器中所有bean的NameString[] beanNames = (this.detectHandlersInAncestorContexts ?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :applicationContext.getBeanNamesForType(Object.class));// Take any bean name that we can determine URLs for.// 遍歷beanNames,并找到這些bean對應的urlfor (String beanName : beanNames) {// 找bean上的所有url(controller上的url+方法上的url),該方法由對應的子類實現String[] urls = determineUrlsForHandler(beanName);if (!ObjectUtils.isEmpty(urls)) {// URL paths found: Let's consider it a handler.// 保存urls和beanName的對應關系,put it to Map<urls,beanName>,該方法在父類AbstractUrlHandlerMapping中實現registerHandler(urls, beanName);}else {if (logger.isDebugEnabled()) {logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");}}} }determineUrlsForHandler(String beanName)方法的作用是獲取每個Controller 中的url,不同的子類有不同的實現,這是一個典型的模板設計模式。因為開發中我們用的最多的就是用注解來配置Controller 中的url , BeanNameUrlHandlerMapping 是
AbstractDetectingUrlHandlerMapping 的子類,處理注解形式的url 映射.所以我們這里以BeanNameUrlHandlerMapping 來進行分析。我們看BeanNameUrlHandlerMapping 是如何查beanName 上所有映射的url。
到這里HandlerMapping 組件就已經建立所有url 和Controller 的對應關系。
?
總結
以上是生活随笔為你收集整理的Spring MVC 源码-初始化阶段的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring MVC 源码分析
- 下一篇: Spring MVC 源码-运行调用阶段