文档章节

spring 从源码学设计1-doDispatch()

e
 enosh
发布于 2014/11/07 17:57
字数 1290
阅读 40
收藏 0
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		int interceptorIndex = -1;

		try {
			ModelAndView mv;
			boolean errorView = false;

			try {
				processedRequest = checkMultipart(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;
					}
				}

				// Apply preHandle methods of registered interceptors.
				HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
				if (interceptors != null) {
					for (int i = 0; i < interceptors.length; i++) {
						HandlerInterceptor interceptor = interceptors[i];
						if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
							triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
							return;
						}
						interceptorIndex = i;
					}
				}

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				// Do we need view name translation?
				if (mv != null && !mv.hasView()) {
					mv.setViewName(getDefaultViewName(request));
				}

				// Apply postHandle methods of registered interceptors.
				if (interceptors != null) {
					for (int i = interceptors.length - 1; i >= 0; i--) {
						HandlerInterceptor interceptor = interceptors[i];
						interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
					}
				}
			}
			catch (ModelAndViewDefiningException ex) {
				logger.debug("ModelAndViewDefiningException encountered", ex);
				mv = ex.getModelAndView();
			}
			catch (Exception ex) {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(processedRequest, response, handler, ex);
				errorView = (mv != null);
			}

			// Did the handler return a view to render?
			if (mv != null && !mv.wasCleared()) {
				render(mv, processedRequest, response);
				if (errorView) {
					WebUtils.clearErrorRequestAttributes(request);
				}
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
							"': assuming HandlerAdapter completed request handling");
				}
			}

			// Trigger after-completion for successful outcome.
			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
		}

		catch (Exception ex) {
			// Trigger after-completion for thrown exception.
			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
			throw ex;
		}
		catch (Error err) {
			ServletException ex = new NestedServletException("Handler processing failed", err);
			// Trigger after-completion for thrown exception.
			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
			throw ex;
		}

		finally {
			// Clean up any resources used by a multipart request.
			if (processedRequest != request) {
				cleanupMultipart(processedRequest);
			}
		}
	}





首先请求会经过各种filter最后进入DispatcherServlet类中的doDispatch方法。这个方法时整个请求转发最核心的方法,请求最终汇聚到这个方法被处理。者个方法时整个spring mvc框架的精华所在。它通过高度抽象的接口描述了一个MVC设计模式的实现方案。

HandlerExecutionChain这个对象是通过请求的url获得的处理器执行链,这个对象里面持有两个属性。一个是处理器,一个是拦截器数组。而请求将会最终通过处理器和拦截器进行处理。这儿的处理器是一个Object是java中最高的抽象,这样的设计有高度的扩展性,这个处理器可以是任何的实现,甚至是一个框架。

HandlerAdapter是一个处理器适配器接口,里面有一个很核心的抽象方法 ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
处理器的执行流程将在这个方法中定义,而且这个方法有高度可扩展性。里面可以实现任何的处理流程。这个方法最后会返回一个视图对象。
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;
					}
				}




这段代码主要是判断用户请求的资源文件有没有被修改。当用户第二次请求同一个资源,服务器端的资源也没有变化,那么这个请求将不会再被执行下去。

HandlerInterceptor是拦截器,这个接口有三个方法
public interface HandlerInterceptor {

	/**
	 * Intercept the execution of a handler. Called after HandlerMapping determined
	 * an appropriate handler object, but before HandlerAdapter invokes the handler.
	 * <p>DispatcherServlet processes a handler in an execution chain, consisting
	 * of any number of interceptors, with the handler itself at the end.
	 * With this method, each interceptor can decide to abort the execution chain,
	 * typically sending a HTTP error or writing a custom response.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler chosen handler to execute, for type and/or instance evaluation
	 * @return <code>true</code> if the execution chain should proceed with the
	 * next interceptor or the handler itself. Else, DispatcherServlet assumes
	 * that this interceptor has already dealt with the response itself.
	 * @throws Exception in case of errors
	 */
	boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
	    throws Exception;

	/**
	 * Intercept the execution of a handler. Called after HandlerAdapter actually
	 * invoked the handler, but before the DispatcherServlet renders the view.
	 * Can expose additional model objects to the view via the given ModelAndView.
	 * <p>DispatcherServlet processes a handler in an execution chain, consisting
	 * of any number of interceptors, with the handler itself at the end.
	 * With this method, each interceptor can post-process an execution,
	 * getting applied in inverse order of the execution chain.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler chosen handler to execute, for type and/or instance examination
	 * @param modelAndView the <code>ModelAndView</code> that the handler returned
	 * (can also be <code>null</code>)
	 * @throws Exception in case of errors
	 */
	void postHandle(
			HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
			throws Exception;

	/**
	 * Callback after completion of request processing, that is, after rendering
	 * the view. Will be called on any outcome of handler execution, thus allows
	 * for proper resource cleanup.
	 * <p>Note: Will only be called if this interceptor's <code>preHandle</code>
	 * method has successfully completed and returned <code>true</code>!
	 * <p>As with the {@code postHandle} method, the method will be invoked on each
	 * interceptor in the chain in reverse order, so the first interceptor will be
	 * the last to be invoked.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler chosen handler to execute, for type and/or instance examination
	 * @param ex exception thrown on handler execution, if any
	 * @throws Exception in case of errors
	 */
	void afterCompletion(
			HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception;

}




preHandle是在处理器处理请求前执行,postHandle是在处理器处理请求后执行,afterCompletion是在 视图渲染完后执行。这样在进入处理流程的前后,视图渲染的前后都可以同过实现一个拦截器实现很多事情。比如spring-mobile就实现了一个DeviceResolverHandlerInterceptor,在preHandle这个方法里面实现创建了一个 Device对象,这个对象可以用来检查请求的来源,是手机,平板还是桌面电脑。
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
         Device device = deviceResolver.resolveDevice(request);
        request.setAttribute(DeviceUtils. CURRENT_DEVICE_ATTRIBUTE, device);
          return true ;
    }





© 著作权归作者所有

共有 人打赏支持
e
粉丝 7
博文 75
码字总数 19035
作品 0
大连
SpringMVC源码剖析(四)- DispatcherServlet请求转发的实现

SpringMVC完成初始化流程之后,就进入Servlet标准生命周期的第二个阶段,即“service”阶段。在“service”阶段中,每一次Http请求到来,容器都会启动一个请求线程,通过service()方法,委派...

相见欢
2013/01/25
0
24
聊聊SpringMVC(2)---SpringMVC之请求过程

1.HttpServletBean HttpServletBean主要参与创建过程,并没有涉及请求的处理。 2.FrameworkServlet FrameworkServlet重写了service,doGet,doPost,doPut,doDelete,doOptions,doTrace方法(......

lemonLove
07/13
0
0
自己手写一个Spring MVC框架

想要了解Spring MVC框架的原理,探究框架是如何设计的,不错的学习方式是阅读源码,然后自己手写一个框架。本文带领大家简化的手写一个Spring MVC框架。 Spring框架对于Java后端程序员来说再...

技术小能手
08/01
0
0
【2016-05-09】SpringMVC结构简介(half done)

前面写了篇文章Jersey vs. SpringMVC从使用角度简单写了下两者的区别,写完后发现对两个框架都不了解,于是搜集了SpringMVC的资料,本文为整理的内容。 一、SpringMVC中重要的概念: Dispat...

rathan0
2016/05/09
26
0
SpringMVC架构设计分享

根据大神的博客 - SpringMVC深度探险系列 - 跟开涛学SpringMVC - 消息转换器HttpMessageConverter - 我自己的SpringMVC源码分析 这里的不全,可以到之前的地方查看SpringMVC源码分析 加上自己...

乒乓狂魔
2015/04/11
0
3

没有更多内容

加载失败,请刷新页面

加载更多

下一页

咕泡-Factory设计模式笔记

个人感悟: 设计模式都是处理复杂问题的,如果问题本身很简单,使用设计模式反而累赘,增加了开发的复杂性 遇到最简单的情况,直接 new 如果创建对象的过程简单,但是需要匹配不同情况,返回...

职业搬砖20年
16分钟前
0
0
Java中的锁分类

在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类。介绍的内容如下: 公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/读写锁 乐观锁/悲观锁 分段锁 偏...

Funcy1122
24分钟前
0
0
Ansible随机数

想为你的Ansible剧本取一个随机数?还想在接下来的运行中保持系统的等幂性?这里有一个答案。 假如,你要为一大批服务器设置cron任务,却不想让它们同时启动,你可以这样设置分钟数: minute...

大别阿郎
33分钟前
0
0
SpringCloud之服务注册中心Eureka

本系列介绍的配置均基于 Spring Boot 2.0.1.RELEASE 版本和 Spring Cloud Finchley.SR1 服务注册中心 Spring Cloud 已经帮我们实现了服务注册中心,我们只需要很简单的几个步骤就可以完成。 ...

熊小飞呀
今天
7
1
“Comparison method violates ...”异常的再现方法

前提条件:JDK8 代码: import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.List;public class Test { public stat......

hunterli
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部