在上一篇博客springMVC源码分析--HandlerInterceptor拦截器(一)中我们介绍了HandlerInterceptor拦截器相关的内容,了解到了HandlerInterceptor提供的三个接口方法:

(1)preHandle: 在执行controller处理之前执行,返回值为boolean ,返回值为true时接着执行postHandle和afterCompletion,如果我们返回false则中断执行
(2)postHandle:在执行controller的处理后,在ModelAndView处理前执行
(3)afterCompletion :在DispatchServlet执行完ModelAndView之后执行

我们可以看到这三个方法的调用过程是不一样的,接下来我们分析一下这个三个方法具体调用实现的地方。其最终实现调用的地方是在doDispatch函数中,因为doDispatch完成了一个请求到返回数据的完整操作。

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

		HandlerExecutionChain mappedHandler = null;

		.......

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

			try {

				.......
				//获取HandlerExecutionChain
				mappedHandler = getHandler(processedRequest);

				......
				//最终会调用HandlerInterceptor的preHandle方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				......
				//最终会调用HandlerInterceptor的postHandle方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			//最终会调用HandlerInterceptor的afterCompletion 方法
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
			//最终会调用HandlerInterceptor的afterCompletion 方法
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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);
				}
			}
		}
	}

mappedHandler.applyPreHandle(processedRequest, response):最终会调用HandlerInterceptor的preHandle方法。在HandlerExecutionChain中的具体实现如下,我们可以看到会调用所有的HandlerInterceptor拦截器并调用其preHandler方法。

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();//获取所有的拦截器
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				if (!interceptor.preHandle(request, response, this.handler)) {//分别调用拦截器的preHandle方法
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}

mappedHandler.applyPostHandle(processedRequest, response, mv):最终会调用HandlerInterceptor的postHandle方法

具体实现是在HandlerExecutionChain中实现如下,就是获取所有的拦截器并调用其postHandle方法。

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();//获取所有拦截器
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = interceptors.length - 1; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				interceptor.postHandle(request, response, this.handler, mv);//分别调用拦截器的postHandle方法
			}
		}
	}

triggerAfterCompletion(processedRequest, response, mappedHandler, ex):最终会调用HandlerInterceptor的afterCompletion 方法
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err):最终会调用HandlerInterceptor的afterCompletion 方法

private void triggerAfterCompletionWithError(HttpServletRequest request, HttpServletResponse response,
			HandlerExecutionChain mappedHandler, Error error) throws Exception {

		ServletException ex = new NestedServletException("Handler processing failed", error);
		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, ex);
		}
		throw ex;
	}
private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response,
			HandlerExecutionChain mappedHandler, Exception ex) throws Exception {

		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, ex);
		}
		throw ex;
	}
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();//获取所有拦截器
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = this.interceptorIndex; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				try {
					interceptor.afterCompletion(request, response, this.handler, ex);//调用拦截器的afterCompletion方法
				}
				catch (Throwable ex2) {
					logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
				}
			}
		}
	}

通过以上代码分析我们可以看到HandlerInterceptor拦截器的最终调用实现是在DispatcherServlet的doDispatch方法中,并且SpringMVC提供了HandlerExecutionChain来帮助我们执行所有配置的HandlerInterceptor拦截器,并分别调用HandlerInterceptor所提供的方法。

springMVC源码分析--HandlerInterceptor拦截器调用过程(二)的更多相关文章

  1. springMVC源码分析--HandlerInterceptor拦截器(一)

    对SpringMVC有所了解的人肯定接触过HandlerInterceptor拦截器,HandlerInterceptor接口给我们提供了3个方法: (1)preHandle: 在执行controll ...

  2. springMVC源码分析之拦截器

    一个东西用久了,自然就会从仅使用的层面上升到探究其原理的层面,在javaweb中springmvc更是如此,越是优秀的框架,其底层实现代码更是复杂,而在我看来,一个优秀程序猿就相当于一名武林高手,不断 ...

  3. springMVC源码分析--视图AbstractView和InternalResourceView(二)

    上一篇博客springMVC源码分析--视图View(一)中我们介绍了简单介绍了View的结构实现及运行流程,接下来我们介绍一下View的实现类做的处理操作. AbstractView实现了rende ...

  4. springMVC源码分析--HttpMessageConverter参数read操作(二)

    上一篇博客springMVC源码分析--HttpMessageConverter数据转化(一)中我们简单介绍了一下HttpMessageConverter接口提供的几个方法,主要有以下几个方法: (1 ...

  5. SpringMVC源码阅读:拦截器

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  6. springMVC源码分析--拦截器HandlerExecutionChain(三)

    上一篇博客springMVC源码分析--HandlerInterceptor拦截器调用过程(二)中我们介绍了HandlerInterceptor的执行调用地方,最终HandlerInterceptor ...

  7. springMVC源码分析--页面跳转RedirectView(三)

    之前两篇博客springMVC源码分析--视图View(一)和springMVC源码分析--视图AbstractView和InternalResourceView(二)中我们已经简单的介绍了View相 ...

  8. 7、SpringMVC源码分析(2):分析HandlerAdapter.handle方法,了解handler方法的调用细节以及@ModelAttribute注解

    从上一篇 SpringMVC源码分析(1) 中我们了解到在DispatcherServlet.doDispatch方法中会通过 mv = ha.handle(processedRequest, res ...

  9. springMVC源码分析--HandlerMethodReturnValueHandlerComposite返回值解析器集合(二)

    在上一篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)我们介绍了返回值解析器HandlerMethodReturnValueHand ...

随机推荐

  1. 关于wooyun-2015-096990的总结

    漏洞url:http://wooyun.jozxing.cc/static/bugs/wooyun-2015-096990.html 摘要 if(!ini_get('register_globals' ...

  2. ●SPOJ LCS2Longest Common Substring II

    题链: http://www.spoj.com/problems/LCS2/题解: 后缀自动机. 对第一个串建立后缀自动机, 然后把后面的每个串分别与该串的自动机去匹配,求出相应的数组val*[s]: ...

  3. hdu 5646DZY Loves Partition(构造)

    DZY Loves Partition  Accepts: 154  Submissions: 843  Time Limit: 4000/2000 MS (Java/Others)  Memory ...

  4. SpringBoot学习之SpringBoot执行器

    在以往的分布式开发当中,各个服务节点的监控必不可少.监控包含有很多方面,比如说:内存占用情况,节点是否健康等.在spring-boot会给我们提供相关资源监控叫做spring-boot-actuato ...

  5. C#+HtmlAgilityPack+Dapper走一波爬虫

    最近因为公司业务需要,又有机会撸winform了,这次的需求是因为公司有项目申报的这块业务,项目申报前期需要关注政府发布的相关动态信息,政府部门网站过多,人工需要一个一个网站去浏览和查阅,有时候还会遗 ...

  6. Python中文件的操作

    文件的操作介绍 文件打开的方法 主要有两种: no with 格式:open(file, mode='r', buffering=-1, encoding=None, errors=None, new ...

  7. c语言的第三次作业

    (一)改错题 计算f(x)的值:输入实数x,计算并输出下列分段函数f(x)的值,输出时保留1位小数. 输入输出样例1: Enterr x: 10.0 f(10.0) = 0.1 输入输出样例2: En ...

  8. 设置思科设备console密码、enable密码、vty登录密码

    思科设备各级密码:1)  console密码 SW2(config)#line console 0SW2(config-line)#password ciscoSW2(config-line)#log ...

  9. Tomcat 报错的解决方法:The APR based Apache Tomcat Native library which allows optimal

    下载 http://tomcat.heanet.ie/native/1.1.12/binaries/win32/tcnative-1.dll将这个文件复制到C:\WINDOWS\system32\,. ...

  10. Java 的异常处理机制

    异常是日常开发中大家都「敬而远之」的一个东西,但实际上几乎每种高级程序设计语言都有自己的异常处理机制,因为无论你是多么厉害的程序员,都不可避免的出错,换句话说:你再牛逼,你也有写出 Bug 的时候. ...