Spring Framework源码(九):SpringMVC之从DispatcherServlet说起

    我们开门见山,首先看看DispatcherServlet这个类的类继承关系:

《Spring Framework源码(九):SpringMVC之从DispatcherServlet说起》

 

     可以看见DispatcherServlet继承自Java Servlet API的HttpServlet类,是一个标准的Servlet,它的初始化是从HttpServletBean开始的,HttpServletBean的init方法覆盖了父类的同名方法:

public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet '" + getServletName() + "'");
		}
		// 将init-param参数绑定到上下文中,方便后续取用
		try {
			PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
			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) {
			logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
			throw ex;
		}
		//由子类提供各自的初始化实现
		initServletBean();

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

    initServletBan是由HttpServletBean的子类FrameworkServlet来实现的:

protected final void initServletBean() throws ServletException {
		//省略代码若干...
		try {
			//初始化web上下文
			this.webApplicationContext = initWebApplicationContext();
			//提供给子类实现自己的初始化逻辑,此处是开发者可以扩展的一个方法
			initFrameworkServlet();
		}
		//省略代码若干...
	}
protected WebApplicationContext initWebApplicationContext() {
		//加载ROOT上下文(ContextLoaderListener加载的上下文)
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;
        
		if (this.webApplicationContext != null) {
			//创建DispatcherServlet注入的上下文
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					if (cwac.getParent() == null) {
						//将当前上下文绑定到ROOT上下文
						cwac.setParent(rootContext);
					}
					//更新当前上下文的状态
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			//如果构造时期没有初始化上下文,则查找已绑定的上下文
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			//如果没有绑定,则从ROOT上下文创建一个当前上下文
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			// 如果当前上下文不是支持refresh操作的 ConfigurableApplicationContext
			//或者构造时期注入的context已经refresh则手动触发onRefresh操作
			onRefresh(wac);
		}

		if (this.publishContext) {
			//将当前上下文作为Servlet上下文的一个属性存储起来
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
			//省略日志代码若干...
		}
		return wac;
	}

     经过以上处理后就完成了父子上下文关系的绑定,如图所示:

 《Spring Framework源码(九):SpringMVC之从DispatcherServlet说起》

     从上面的代码不难看出当ROOT上下文和Dispatcher的上下文都创建了以后会调用onRefresh来完成一些子类的逻辑。DispatcherServlet类正好覆盖了这个方法:

protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}
	protected void initStrategies(ApplicationContext context) {
		//初始化文件上传解析器
		initMultipartResolver(context);
		//初始化国际化解析器
		initLocaleResolver(context);
		//初始化主题解析器
		initThemeResolver(context);
		//初始化URL匹配控制器
		initHandlerMappings(context);
		//初始化URL匹配控制器关联的适配器
		initHandlerAdapters(context);
		//初始化匹配异常处理器
		initHandlerExceptionResolvers(context);
		//初始化视图匹配解释器
		initRequestToViewNameTranslator(context);
		//初始化视图渲染处理器
		initViewResolvers(context);
		//初始化FlashMap管理器,通常与重定向转存model等使用场景有关
		initFlashMapManager(context);
	}

    DispatcherServlet覆盖了父类的doService方法,这个方法会在Servlet处理请求时调用,doService会用到上述代码所初始化的各种策略对象。在doService中设置好了各项策略对象后会调用DispatcherServlet的核心方法doDispatch,接下来我们就详细了解下这个方法:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;
                //这里是一个并发请求管理器,spring使用了多线程来处理并发请求
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		try {
			ModelAndView mv = null;
			Exception dispatchException = null;
			try {
				//检查请求中是否有上传文件
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);        
				// 为request寻找合适的handler处理器
				mappedHandler = getHandler(processedRequest);
				//省略未找到异常处理代码
				// 根据handler处理器选择合适的适配器
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
				//如果handler支持http报文头的last-modified字段解析则处理之
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
                                //启用handler的前置过滤器,如果未达到要求则立即返回
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
				//调用handle方法处理请求返回ModelAndView对象
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
                                //如果mv中未设置返回的视图名则启用默认视图名
				applyDefaultViewName(request, mv);
				//启用handler的后置过滤器
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			//处理返回的ModelAndView,用合适的ViewResolver渲染页面再将页面返回给浏览器
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		//省略代码若干...
}

     doDispatch这个核心方法大致描述了整个web请求流程,也道出了springmvc比较核心的两部分request->model和model->response。

     此外,再说点题外话,SpringMVC提供了一些的比如RequestHandler,HandlerAdapter等类的默认实现类,关于这些默认类的信息都配置在DispatcherServlet同名目录下的DispatcherServlet.properties文件中。

    下节预告

    下节中我们将单独抽离出文件上传模块细讲,还将着重分析下SpringMVC的数据绑定、验证、转换部分

   

    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/flashflight/article/details/42871639
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞