SpringMVC之DispatchServlet初始化过程

  SpringMvc最核心的类就是前端控制器DispatchServlet,作为一个Servlet,是整个SpringMvc的入口,用于调度其他的各组件工作,如Controller、HandlerMapping、ViewResolver等,控制着整个处理用户请求的流程,本篇首先来总结一下DispatchServlet的初始化过程,及进行具体处理请求前的预准备

作为一个Servlet的主要继承关系:HttpServletBean -- > FrameworkServlet -- > DispatchServlet,分别分析这三个类,各自所做的工作,就基本上总结了整个DispatchServlet的初始过程

1、HttpServletBean

重写了GenericServlet的init方法,servelt实例化时init方法会被调用:

    @Override
	public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet '" + getServletName() + "'");
		}

		//将Servlet的初始化参数(initParam)保存在PropertyValues,并检查Servlet的初始化参数包含了所必须的参数,子类可以将在this.requiredProperties指定必须的参数
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
		if (!pvs.isEmpty()) {
			try {
                      //BeanWrapper就是对象的包裹者,主要用于对象的属性设置,这里的this,就是DispatchServlet
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
                      //ServletContext的资源加载器,使用本质上是使用ServletContext对象来获取与当前Servlet相关的资源
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
                      //自定义了属性编辑器,用于编辑被包裹对象的属性
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
                       //空方法留给子类自定义初始化BeanWrapper
				initBeanWrapper(bw);
              	        //将Servlet的初始化参数设置到BeanWrapper中
				bw.setPropertyValues(pvs, true);
			}
			catch (BeansException ex) {
				if (logger.isErrorEnabled()) {
					logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
				}
				throw ex;
			}
		}

		//在FrameworkServlet中实现
		initServletBean();

		if (logger.isDebugEnabled()) {
			logger.debug("Servlet '" + getServletName() + "' configured successfully");
		}
	}

总结:主要使用ServletConfig配置信息初始化DispatchServlet的一些属性,如使用web.xml时配置的contextConfigLocation

 

2、FrameworkServlet

1)重写initServletBean()初始化IOC容器

调用链:HttpServletBean.init()-->FrameworkServlet.initServletBean()

    @Override
	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 {
                  //初始化ioc容器(设置父子容器并刷新)
			this.webApplicationContext = initWebApplicationContext();
                  //空方法,留给子类扩展
			initFrameworkServlet();
		}
		...
	}

核心方法initWebApplicationContext():

protected WebApplicationContext initWebApplicationContext() {
  		//根据ServletContext.getAttribute来获取到WebApplicationContext(根容器),而获取到的根容器是之前由ContextLoaderListener(ServletContextListener)的contextInitialized方法将根容器保存在了ServletContext
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;
  		//this.webApplicationContext为子容器(保存SpringMVC组件),如果我们使用的是配置类的方式即继承AbstractAnnotationConfigDispatcherServletInitializer来指定创建父子容器,那么在Servlet容器启动的时侯webApplicationContext就被创建了
		if (this.webApplicationContext != null) {     
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					if (cwac.getParent() == null) {
                     	          //将根容器设置为子容器(保存SpringMVC组件)的父容器
						cwac.setParent(rootContext);
					}
                                //配置并且刷新容器(启动初始化容器过程),之前的父子容器只是被创建没有调用refresh
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
  		
		if (wac == null) {
                 //如果子容器还没又被创建,尝试去ServletContext中以获取
			wac = findWebApplicationContext();
		}
		if (wac == null) {
                 //如果子容器还为空,就通过web.xml配置的参数contextConfigLocation指定的Xml配置文件路径来创建一个XmlWebApplicationContext类型的ioc子容器,设置父子容器关系,并刷新。
			wac = createWebApplicationContext(rootContext);
		}
		
		if (!this.refreshEventReceived) {
                 //在DispatchServlet中实现
			onRefresh(wac);
		}
		//this.publishContext指定是否将web容器发布在ServletContext中,默认为ture
		if (this.publishContext) {
			String attrName = getServletContextAttributeName();
          	    //将初始化好的ioc容器放入ServletContext中
			getServletContext().setAttribute(attrName, wac);
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
						"' as ServletContext attribute with name [" + attrName + "]");
			}
		}

		return wac;
	}

FrameworkServlet的initServletBean方法主要就是初始化IOC容器,包括一个子容器(保存springmvc组件,如Controller、ViewResolver、HandlerMapping等等)和一个父容器(保存业务逻辑组件,如service,dao),

2)重写了HttpServelt的service方法
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
	if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
      	    //处理PATCH请求
		processRequest(request, response);
	}
	else {
      	    //如果不是PATCH请求,调用HttpServelt.service()
		super.service(request, response);
	}
}

FrameworkServlet也重写了doGet、doPost、xxx等对应处理各类型请求的方法,最终都是调用了processRequest(request, response)来处理:

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   long startTime = System.currentTimeMillis();
   Throwable failureCause = null;
   //获取之前LocaleContext(主要作用是封装请求的 Locale 信息,主要就是语言信息)默认不存在
   LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
  //创建本次请求的localeContext
   LocaleContext localeContext = buildLocaleContext(request);
	//获取之前RequestAttributes(封装request,response)默认不存在
   RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
  	//创建本次请求的requestAttributes
   ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
	//与异步请求相关的处理
   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
   asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
	//将localeContext、requestAttributes分别保存在LocaleContextHolder、RequestContextHolder中,两者都是使用ThreadLocal与当前线程绑定
   initContextHolders(request, localeContext, requestAttributes);

   try {
     //真正的处理请求过程在DispatchServlet中实现
      doService(request, response);
   }
   catch (ServletException ex) {
      failureCause = ex;
      throw ex;
   }
   catch (IOException ex) {
      failureCause = ex;
      throw ex;
   }
   catch (Throwable ex) {
      failureCause = ex;
      throw new NestedServletException("Request processing failed", ex);
   }

   finally {
     //完成请求默认移除requestAttributes和localeContext
      resetContextHolders(request, previousLocaleContext, previousAttributes);
      if (requestAttributes != null) {
         requestAttributes.requestCompleted();
      }

      if (logger.isDebugEnabled()) {
         if (failureCause != null) {
            this.logger.debug("Could not complete request", failureCause);
         }
         else {
            if (asyncManager.isConcurrentHandlingStarted()) {
               logger.debug("Leaving response open for concurrent processing");
            }
            else {
               this.logger.debug("Successfully completed request");
            }
         }
      }
	  //无论请求是否成功都会发布请求处理完成事件(我们可以向容器中添加相应的事件监听器)
      publishRequestHandledEvent(request, response, startTime, failureCause);
   }
}

总结:1、在Servlet初始化阶段,初始化了IOC容器

           2、在处理请求阶段,做了一些提前的准备工作

 

3、DispatcherServlet

1)重写onRefresh,初始化SpringMvc工作组件

HttpServletBean.init()-->FrameworkServlet.initServletBean()-->FrameworkServlet.initWebApplicationContext()-->DispatcherServlet.onRefresh(ApplicationContext context)

@Override
protected void onRefresh(ApplicationContext context) {
  //context就是在FrameworkServlet.initWebApplicationContext()中完成初始化工作的IOC容器
   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); }

这里我们以处理器映射器的初始化initHandlerMappings(context)为例分析,其他组件的初始化处理也类似

private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;
  		//this.detectAllHandlerMappings默认为true
		if (this.detectAllHandlerMappings) {
			//在容器中找到所有的HandlerMapping
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
              //将所有的HandlerMapping保存在handlerMappings中
				this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
				// 排序
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}

		//如果在IOC容器中没有找到任何的HandlerMapping,获取默认的HandlerMapping
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}

getDefaultStrategies(context, HandlerMapping.class)获取默认的组件:

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
  //这的key为org.springframework.web.servlet.HandlerMapping
   String key = strategyInterface.getName();
  //在defaultStrategies获取我们需要创建的组件的类型,多个的话,使用逗号隔开
   String value = defaultStrategies.getProperty(key);
   if (value != null) {
     //使用逗号为分隔符,转化成数组
      String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
      List<T> strategies = new ArrayList<T>(classNames.length);
     //遍历classNames利用反射创建对象
      for (String className : classNames) {
         try {
            Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
           //创建并添加到IOC容器中
            Object strategy = createDefaultStrategy(context, clazz);
            strategies.add((T) strategy);
         }
         catch (ClassNotFoundException ex) {
            throw new BeanInitializationException(
                  "Could not find DispatcherServlet's default strategy class [" + className +
                        "] for interface [" + key + "]", ex);
         }
         catch (LinkageError err) {
            throw new BeanInitializationException(
                  "Error loading DispatcherServlet's default strategy class [" + className +
                        "] for interface [" + key + "]: problem with class file or dependent class", err);
         }
      }
      return strategies;
   }
   else {
      return new LinkedList<T>();
   }
}
//保存了各组件接口对应的默认实现类
private static final Properties defaultStrategies;
//静态代码块,用于初始化defaultStrategies
static {
   try {
     //private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties",创建了一个与DispatcherServlet.class处于同一包下的DispatcherServlet.properties文件的资源对象
      ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
      //创建Properties对象,保存了组件接口的对应的默认实现类
      defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
   }
   catch (IOException ex) {
      throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
   }
}

DispatcherServlet.properties配置文件中指定了各组件的默认实现类的全类名:

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
   org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
   org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
   org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
   org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
   org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

各个SpringMvc工作组件的初始化过程为:首先从IOC容器中找对应接口类型的组件,如果没到,就创建一个在DispatcherServlet.properties中指定的默认组件接口实现类的实例

2)重写doService,进入核心方法doDispatch(request, response)
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   if (logger.isDebugEnabled()) {
      String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
      logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
            " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
   }

 	//这里与RequestDispatcher.include()相关
   Map<String, Object> attributesSnapshot = null;
   if (WebUtils.isIncludeRequest(request)) {
      attributesSnapshot = new HashMap<String, Object>();
      Enumeration<?> attrNames = request.getAttributeNames();
      while (attrNames.hasMoreElements()) {
         String attrName = (String) attrNames.nextElement();
         if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
            attributesSnapshot.put(attrName, request.getAttribute(attrName));
         }
      }
   }

   //将一些组件设置到request中
   request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
   request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
   request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
   request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

   FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
   if (inputFlashMap != null) {
      request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
   }
   request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
   request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

   try {
     //最终调用了
      doDispatch(request, response);
   }
   finally {
      if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
         // Restore the original attribute snapshot, in case of an include.
         if (attributesSnapshot != null) {
            restoreAttributesAfterInclude(request, attributesSnapshot);
         }
      }
   }
}

最终进入doDispatch(request, response),作为DispatchServlet最核心方法,调度着各工作组件进行具体的请求处理。

 

posted @ 2019-07-07 21:09  ◆╮提笔写惆怅?  阅读(1403)  评论(0编辑  收藏  举报