文档章节

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
【2016-05-09】SpringMVC结构简介(half done)

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

rathan0
2016/05/09
26
0
从 0 开始手写一个 Spring MVC 框架

从 0 开始手写一个 Spring MVC 框架,向高手进阶! Spring框架对于Java后端程序员来说再熟悉不过了,以前只知道它用的反射实现的,但了解之后才知道有很多巧妙的设计在里面。如果不看Spring的...

DemonsI
08/20
0
0
自己手写一个Spring MVC框架

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

技术小能手
08/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

LINUX中如何查看某个端口是否被占用(转发)

LINUX中如何查看某个端口是否被占用 之前查询端口是否被占用一直搞不明白,问了好多人,终于搞懂了,现在总结下: 1.netstat -anp |grep 端口号 如下,我以3306为例,netstat -anp |grep 33...

覃大光
32分钟前
0
0
JBolt 1.5.0新版发布,升级到支持最新版JFinal和Jetty,实现了在线更新插件功能

JBolt是一个JFinal极速开发框架 定制版IDE插件 目前仅有Eclipse插件版,Idea插件版正在开发中。 JBolt的详细使用教程请移步到这里 =====版本1.5.0 更新内容 2018年10月13日10:41:52===== 注意...

山东-小木
35分钟前
0
0
laravel 微信支付

1.composer加载laravel微信支付第三方文件 composer require "overtrue/laravel-wechat:~4.0" composer require simplesoftwareio/simple-qrcode 1.3.* //composer生成二维码文件 2.改confi......

vio小黑
48分钟前
1
0
学习设计模式——抽象工厂模式

1. 认识抽象工厂模式 1. 定义:提供一个创建一系列相关或互相依赖的对象的接口,而无需指定它们具体的类。 2. 组成结构: AbstractFactory:抽象工厂类,定义创建一系列对象的操作接口 Fact...

江左煤郎
48分钟前
2
0
ES6的let块级作用域和变量不可提升导致一个比较容易出现的错误

今天在写NodeJS代码的时候出现一个变量一直提示未定义,简化后的代码如下: let param = 1;{ console.log(param);} 就在想,不至于啊。不是继承上层的声明吗? 继续看下去,发现原来...

MKjy
54分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部