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框架中使用的组件较多、处理逻辑较复杂。

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