spring源碼解析-web系列(一):啓動

spring源碼解析-web系列(一):啓動
spring源碼解析-web系列(二):處理請求的過程
spring源碼解析-web系列(三):九大組件之HandlerMapping
spring源碼解析-web系列(四):九大組件之HandlerAdapter
spring源碼解析-web系列(五):解析請求參數
spring源碼解析-web系列(六):九大組件之ViewResolver
spring源碼解析-web系列(七):九大組件之HandlerExceptionResolver

轉載請標明出處:
https://blog.csdn.net/bingospunky/article/details/97262392
本文出自馬彬彬的博客

俯視spring web

我們在使用spring-mvc時,一般會:

1、在web.xml中配置一個***contextConfigLocation***參數,值爲spring的xml配置文件(不包含controller)路徑,然後再配置一個 ContextLoaderListener 類型的listener。
2、配置一個DispatcherServlet類型的servlet,給該servlet配置contextConfigLocation類型的參數,值爲spring的xml配置文件(只包含controller)路徑。

在監聽器ContextLoaderListener加載的過程中,會根據contextConfigLocation對應的xml內容構造一個ApplicationContext,默認類型爲XmlWebApplicationContext。這個ApplicationContext與j2ee的ServletContext綁定的,作爲該項目的rootApplicationContext。

在DispatcherServlet加載過程中,會根據servlet裏配置的xml文件構造一個WebApplicationContext,每個DispatcherServlet對應一個WebApplicationContext。

WebApplicationContext

一個DispatcherServlet對應一個WebApplicationContext,在org.springframework.web.servlet.FrameworkServlet.initServletBean方法中創建,且保證執行一次refresh方法,該WebApplicationContext的parent是上述的rootApplicationContext。
一般項目中定義一個DispatcherServlet,也就是一個WebApplicationContext。同時spring支持存在多個DispatcherServlet,使用不同的配置響應不同的servlet。

刷新過程

1.FrameworkServlet的createWebApplicationContext方法創建WebApplicationContext,創建完成後會調用FrameworkServlet.configureAndRefreshWebApplicationContext方法刷新配置。

2.在configureAndRefreshWebApplicationContext方法中,先添加一個事件監聽,監聽ContextRefreshedEvent。

3.調用剛纔創建的WebApplicationContext的refresh方法,該方法代碼如下:

代碼1 (org.springframework.context.support.AbstractApplicationContext.refresh):

   @Override
   public void refresh() throws BeansException, IllegalStateException {
      synchronized (this.startupShutdownMonitor) {
         // Prepare this context for refreshing.
         prepareRefresh();

         // Tell the subclass to refresh the internal bean factory.
         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

         // Prepare the bean factory for use in this context.
         prepareBeanFactory(beanFactory);

         try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // Check for listener beans and register them.
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();
         }

         catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
               logger.warn("Exception encountered during context initialization - " +
                     "cancelling refresh attempt: " + ex);
            }

            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();

            // Reset 'active' flag.
            cancelRefresh(ex);

            // Propagate exception to caller.
            throw ex;
         }

         finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
         }
      }
   }

代碼1 先清空beanFactory,獲取一個純淨的beanFactory,然後添加各種PostProcessor,然後調用finishBeanFactoryInitialization(beanFactory);方法初始化所有非懶惰bean。最後調用finishRefresh();發送ContextRefreshedEvent事件。

4.第2步添加的事件監聽被回調,調用FrameworkServlet.this.onApplicationEvent(event);方法,先標記FrameworkServlet.refreshEventReceived爲true,表示已經刷新的web相關信息,進而調用DispatcherServlet.onRefresh方法刷新web相關信息,比如:HandlerMapping、ViewResolver等。

代碼2 (org.springframework.web.servlet.DispatcherServlet):

	@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

代碼2初始化不同組件思路是相似的,都是先去BeanFactory里根據類型獲取相關對象,然後把這些對象存儲在DispatcherServlet對應的變量裏。

5.如果FrameworkServlet.refreshEventReceived對象爲false,刷新web相關信息,這裏已經在事件監聽裏刷新過了,所以不會再刷新一次。

總結

如果俯視spring mvc的話,在一個web項目中,會有一個ApplicationContext作爲rootApplicationContext和ServletContext相互關聯。對於每個DispatcherServlet,都有一個ApplicationContext和它對應。

如果平時spring mvc的話,它和其他的spring模塊(或者別的框架)有着相同的模式,在啓動時通過各種配置文件把需要的組件初始化到合適的位置;當使用時,在適當的位置直接獲取它們。就像是Mybatis把相關組件都存在Configuration類裏一樣。區別就是spring-mvc框架中使用的組件較多、處理邏輯較複雜。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章