在上一篇博客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. 将 Net 项目升级 Core项目经验:(一)迁移Net项目为Net Core\Standard项目

    迁移Net项目为Net Core\Standard项目 背景: 我们公司内部有自己ORM开发框架,最新因为需要将系统迁移到国产服务器上,所以首先需要将最基础的ORM框架改造可以运行在国产服务器上.对于 ...

  2. StandardContext

    错误信息: 2014-2-6 21:37:19 org.apache.catalina.startup.HostConfig checkResources信息: Reloading context [ ...

  3. [ZJOI 2014]力

    Description 给出n个数qi,给出Fj的定义如下: $$F_j = \sum_{i<j}\frac{q_i q_j}{(i-j)^2 }-\sum_{i>j}\frac{q_i ...

  4. [ZJOI 2006]超级麻将

    Description Input 第一行一个整数N(N<=100),表示玩了N次超级麻将. 接下来N行,每行100个数a1..a100,描述每次玩牌手中各种牌的数量.ai表示数字为i的牌有ai ...

  5. PKUWC2018划水记

    PKUWC2018划水记 Day -1 ​ 从福州出发去长沙,原本是预定Day0当天的航班,后来怕来不及提前到了今天. ​ 由于最近长沙下雪,所以听说飞机取消了很多班次,所以早上起来的时候还特地看了一 ...

  6. hdu 5011(博弈)

    题意:在许多堆石子中,两人轮流取,1.在一堆中取至少一个  2.将这一堆分成两堆 思路:NIM游戏,所有值的异或,当其为0时失败 nim游戏: 假设只有两堆,游戏人取得胜利并不在于N1和N2的值具体是 ...

  7. hdu 5392

    Sample Input 2 3 1 3 2 6 2 3 4 5 6 1   Sample Output 2 6 题意:给一个转置求它的循环长度 题解:分解成循环求最小公倍数 #include< ...

  8. UVA140 ——bandwidth(搜索)

    Given a graph (V,E) where V is a set of nodes and E is a set of arcs in VxV, and an ordering on the ...

  9. MQ(消息队列)常见的应用场景解析

    前言 提高系统性能首先考虑的是数据库的优化,之前一篇文章<数据库的使用你可能忽略了这些>中有提到过开发中,针对数据库需要注意的事项.但是数据库因为历史原因,横向扩展是一件非常复杂的工程,所 ...

  10. python中如何将生成等差数列和等比数列

    在python库numpy 中提供了函数linspace和logspace函数用于生产等差数列和等比数列.     1.linspace函数生成等差数列 def linspace(start, sto ...