SpringMVC源码学习(一)--------主处理流程

在学习SpringMvc源码之前,我们可以先回忆一下,我们觉得SpringMvc到底帮我们做了什么,然后我们才来学习springMVc到底是怎么做的。

1.提供了更丰富自由的路由规则
2.不需要用户编写request中参数绑定到实体的成员变量的代码
3.有丰富的参数绑定方式,例如路径的值可以绑定到参数中
4.不需要自己编写响应处理的代码,直接返回实体,框架就会帮我们处理成对应的响应
5.可以更方便的利用spring的特性

这次我们学习SpringMVC的处理流程,首先我们要知道一个请求过来,进入到servlet容器,会根据请求路径路由到相应的servlet处理器,并调用doService方法,而SpringMVC实现了一个特别的servlet.这个特别的servlet就是DispatcherServlet。DispatcherServlet的映射路径会配置成"/",所以这个servlet会接收所有请求。
那么我们首先来看一下这个DispacherServlet的doService方法。

@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) + "]");
	}

	// Keep a snapshot of the request attributes in case of an include,
	// to be able to restore the original attributes after the 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));
			}
		}
	}

	// Make framework objects available to handlers and view objects.
	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);
			}
		}
	}
}

可以看到,这段代码有很大一部分代码是给request设置一些属性,例如 webApplicationContext、localeResolve、themeResolver等等,
这些属性应该是便于以后处理使用。
然后就是调用doDispatch方法,处理请求。
最后还有一些异步请求的处理,这部分只能留到讲解异步请求的时候解释。

接着来看doDispatch方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;
		
		//根据请求获取WebAsyncdManager,这类是跟异步处理有关
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			//这个类用于存储了Model跟View的信息
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				//这个处理跟文件上传有关,如果请求中包含文件上传,会返回一个封装过的HttpServletRequest
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				//根据请求获取处理调用链,这个链包含了具体handler和拦截器。
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					//如果找不到处理器就直接返回
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				//根据处理器找到对应的适配器,因为有多种处理器,这里spring使用了适配器模式,使得调用统一。
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				//如果是get请求或head请求,则根据请求调用handlerAdapter的getLastModified方法,如果已是最新的响应则直接返回。
				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;
					}
				}
				//调用拦截器的预处理方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				//处理请求,并返回modelAndView对象
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				
				//如果是异步处理则返回
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				
				//???????
				applyDefaultViewName(processedRequest, mv);
				//调用拦截器的后处理方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			//处理响应
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			//处理过程出现异常则触发最后处理
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			//这里跟异步处理有关,稍后再做解释
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				//处理文件上传相关的资源
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

这里总结一下springMVC处理请求的逻辑算法大概有以下步骤:
1.检查是否有文件上传,并返回HttpServletRequest
2.根据请求获取处理调用链,这个链封装了具体handler和拦截器。
3.根据处理器找到对应的适配器,因为有多种处理器,这里spring使用了适配器模式,使得调用统一。
4.如果是get请求或head请求,则根据请求调用handlerAdapter的getLastModified方法,如果已是最新的响应则直接返回。
5.调用拦截器的预处理方法
6.处理请求,并返回modelAndView对象
7.如果是异步处理则返回到servlet容器
8.调用拦截器的后处理方法
9.处理响应
10.最后,有一个异步相关的处理和如果是含有文件上传需要清理资源 。

接着我们来看一下,getHandler方法,这一步是根据请求获取处理调用链。

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		//成员变量List<HandlerMapping> handlerMappings
		//遍历handlerMappings
		for (HandlerMapping hm : this.handlerMappings) {
			if (logger.isTraceEnabled()) {
				logger.trace(
						"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
			}
			//调用HandlerMapping.getHandler方法,获取调用链。
			HandlerExecutionChain handler = hm.getHandler(request);
			//如果hanlder不为空,返回handler,为空,继续遍历,直到所有HandlerMapping都被遍历为止
			if (handler != null) {
				return handler;
			}
		}
		//没有找到对应的hanlder直接返回
		return null;
	}

这里逻辑很简单,但涉及了一个组件,就是HandlerMapping。

public interface HandlerMapping{
	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

这个接口就只定义了一个方法,就是根据请求获取HandlerExecutionChain,也就是这个接口定义了路由的规则。具体的规则都定义在了这个接口的实现类中,因为有许多实现类,所以提供了丰富的路由规则。
后面会更深入的讨论这个接口的实现类。

继续看一下getHandlerAdapter,即根据处理器找到对应的适配器这一步

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		//List<HandlerAdapter> handlerAdapters
		//遍历handlerAdapters
		for (HandlerAdapter ha : this.handlerAdapters) {
			if (logger.isTraceEnabled()) {
				logger.trace("Testing handler adapter [" + ha + "]");
			}
			//调用HandlerAdapter.supports接口,如果支持则返回
			if (ha.supports(handler)) {
				return ha;
			}
		}
		//如果没找到则抛出异常
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

这里的处理逻辑跟上面根据请求获取处理调用链的逻辑差不多,都是遍历所有现有的HandlerAdapter,直到找到适合的HandlerAdapter返回。
而这里就涉及了另一个组件HandlerAdapter。

public interface HandlerAdapter {
	//返回是否支持调用handler
	boolean supports(Object handler);
	//执行hanler,并返回ModelAndView
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
	//获取请求的最后修改时间
	long getLastModified(HttpServletRequest request, Object handler);
}

这个组件的实现类的handle方法,主要做这3件事
第一、把request转换成参数
第二、调用具体的handler进行请求处理
第三、有部分实现还直接处理的响应
后面会更深入的讨论这个接口的实现类。

总结:
springMvc处理请求的流程其实非常简单,无非就是先根据请求找到对应的handler,然后再找到对应的handlerAdapter,然后就处理请求,但其实有很多处理细节,这些留在后面再做解释。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值