springmvc流程大致分析4 DispatcherServlet请求转发

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qwkxq/article/details/55002465
DispatcherServlet跟所有servlet一样都是通过service来接收客户端的请求,然后判断请求类型,然后进入对应的
doXxx方法的(这些方法在FrameworkServlet中被复写),以doGet方法为例:
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		processRequest(request, response);
	}

可以看到实际上处理doGet是在processRequest中被处理的,

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

		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;

		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		LocaleContext localeContext = buildLocaleContext(request);

		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes requestAttributes = null;
		if (previousAttributes == null || (previousAttributes instanceof ServletRequestAttributes)) {
			requestAttributes = new ServletRequestAttributes(request);
		}

		initContextHolders(request, localeContext, requestAttributes);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), getRequestBindingInterceptor(request));

		try {
			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 {
			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()) {
						if (logger.isDebugEnabled()) {
							logger.debug("Leaving response open for concurrent processing");
						}
					}
					else {
						this.logger.debug("Successfully completed request");
					}
				}
			}
			if (this.publishEvents) {
				// Whether or not we succeeded, publish an event.
				long processingTime = System.currentTimeMillis() - startTime;
				this.webApplicationContext.publishEvent(
						new ServletRequestHandledEvent(this,
								request.getRequestURI(), request.getRemoteAddr(),
								request.getMethod(), getServletConfig().getServletName(),
								WebUtils.getSessionId(request), getUsernameForRequest(request),
								processingTime, failureCause));
			}
		}
	}

processRequest的大致逻辑是:

以doService方法为界点,

之前的代码主要就是从request中取出当前的请求对象和属性分别设置到2个ThreadLocal对象中:
LocaleContextHolder和RequestContextHolder,也就是对象和属性都被绑定在当前请求线程上了。

之后的代码主要就是对LocaleContextHolder和RequestContextHolder的请求对象和属性进行解绑,
以及发布一个ServletRequestHandledEvent事件,可以通过注册监听器监听该事件。

可以看到processRequest方法其实也只是做了一些request参数的绑定和解绑,而真正处理请求的方法是doService,
doService是一个抽象方法,由DispatcherServlet重写
,代码如下:

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {

		if (logger.isDebugEnabled()) {
			String requestUri = urlPathHelper.getRequestUri(request);
			String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
			logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
					" processing " + request.getMethod() + " request for [" + requestUri + "]");
		}

		// 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)) {
			logger.debug("Taking snapshot of request attributes before include");
			attributesSnapshot = new HashMap<String, Object>();
			Enumeration<?> attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
				if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
					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()) {
				return;
			}
			// Restore the original attribute snapshot, in case of an include.
			if (attributesSnapshot != null) {
				restoreAttributesAfterInclude(request, attributesSnapshot);
			}
		}
	}

DispatcherServlet的doService逻辑主要是将前面初始化的容器上下文,本地解析器等springmvc编程元素设置到
request中,供下一步使用,而真正完成请求转发是在doDispatch方法中被处理,它封装了springmvc处理请求转发的所有流程,其定义如下:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = processedRequest != request;

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest, false);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						String requestUri = urlPathHelper.getRequestUri(request);
						logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				try {
					// Actually invoke the handler.
					mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				}
				finally {
					if (asyncManager.isConcurrentHandlingStarted()) {
						return;
					}
				}

				applyDefaultViewName(request, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				return;
			}
			// Clean up any resources used by a multipart request.
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}

doDispatch方法逻辑大概是:

1.mappedHandler = getHandler(processedRequest, false);
遍历之前初始化HandlerMapping列表(handlerMappings,在onRefresh中初始化),返回第一个调用getHandler
不为空的对象,得到HandlerExecutionChain对象。

而HandlerMapping对象的getHandler方法传入HttpservletRequest参数,意味着HandlerMapping可以根据request
的任意信息来决定生成HandlerExecutionChain的策略,如请求头,url路径,cookie,session(最常用还是url路径)

这意味着,我们可以自己编写HandlerMapping实现类,自定义根据request的哪个信息来生成HandlerExecutionChain。

HandlerExecutionChain主要由

private final Object handler;
private HandlerInterceptor[] interceptors;
组成,

其中handler代表HandlerAdapter实际执行的处理对象,它被定义成Object的意义在于你可以将java中的任意对象定义成
Handler来执行,返回最后的视图。

而handler执行前后,HandlerInterceptor列表将被依次执行,它可以看做是最handler执行方法的环绕通知,用于对handler
执行方法进行方便的处理和扩展,拦截器一般是自定义的。

2.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
遍历之前初始化的HandlerAdapter列表(handlerAdapters),返回第一个supports方法为true的对象,
得到HandlerAdapter对象。

我们也可以通过自定义的HandlerAdapter来执行handler对象。

3.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
HandlerAdapter对象调用handle方法,返回ModelAndview对象。

ModelAndview是springmvc中视图和模型数据的聚合,而视图则抽象成View接口了。
View接口定义了一个render方法用于渲染视图。其实现类包含在HandlerAdapter对象执行handle方法的返回值
中(ModelAndview),而返回的ModelAndview到View有一个视图解析的过程,所以返回的ModelAndview即可以
包含真正的视图View,也可以仅仅包含视图名,springmvc的视图解析器负责将视图名转成真正的视图对象。

扫描二维码关注公众号,回复: 3280284 查看本文章


至此,springmvc的请求处理流程结束。

猜你喜欢

转载自blog.csdn.net/qwkxq/article/details/55002465