springMVC源码分析--HandlerInterceptor拦截器调用过程(二)
在上一篇博客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拦截器调用过程(二)的更多相关文章
- springMVC源码分析--HandlerInterceptor拦截器(一)
对SpringMVC有所了解的人肯定接触过HandlerInterceptor拦截器,HandlerInterceptor接口给我们提供了3个方法: (1)preHandle: 在执行controll ...
- springMVC源码分析之拦截器
一个东西用久了,自然就会从仅使用的层面上升到探究其原理的层面,在javaweb中springmvc更是如此,越是优秀的框架,其底层实现代码更是复杂,而在我看来,一个优秀程序猿就相当于一名武林高手,不断 ...
- springMVC源码分析--视图AbstractView和InternalResourceView(二)
上一篇博客springMVC源码分析--视图View(一)中我们介绍了简单介绍了View的结构实现及运行流程,接下来我们介绍一下View的实现类做的处理操作. AbstractView实现了rende ...
- springMVC源码分析--HttpMessageConverter参数read操作(二)
上一篇博客springMVC源码分析--HttpMessageConverter数据转化(一)中我们简单介绍了一下HttpMessageConverter接口提供的几个方法,主要有以下几个方法: (1 ...
- SpringMVC源码阅读:拦截器
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...
- springMVC源码分析--拦截器HandlerExecutionChain(三)
上一篇博客springMVC源码分析--HandlerInterceptor拦截器调用过程(二)中我们介绍了HandlerInterceptor的执行调用地方,最终HandlerInterceptor ...
- springMVC源码分析--页面跳转RedirectView(三)
之前两篇博客springMVC源码分析--视图View(一)和springMVC源码分析--视图AbstractView和InternalResourceView(二)中我们已经简单的介绍了View相 ...
- 7、SpringMVC源码分析(2):分析HandlerAdapter.handle方法,了解handler方法的调用细节以及@ModelAttribute注解
从上一篇 SpringMVC源码分析(1) 中我们了解到在DispatcherServlet.doDispatch方法中会通过 mv = ha.handle(processedRequest, res ...
- springMVC源码分析--HandlerMethodReturnValueHandlerComposite返回值解析器集合(二)
在上一篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)我们介绍了返回值解析器HandlerMethodReturnValueHand ...
随机推荐
- 认识JQuery,JQuery的优势、语法、多库冲突、JS原生对象和JQuery对象之间相互转换和DOM操作,常用的方法
(一)认识JQuery JQuery是一个JavaScript库,它通过封装原生的JavaScript函数得到一套定义好的方法 JQuery的主旨:以更少的代码,实现更多的功能 (二)JQue ...
- NoClassDefFoundError: org/apache/commons/lang3/StringUtils
出错信息: 2014-2-5 21:38:05 org.apache.catalina.core.StandardContext filterStart严重: Exception starting f ...
- 控制公司 Controlling Companies
题目描述 有些公司是其他公司的部分拥有者,因为他们获得了其他公司发行的股票的一部分.(此处略去一句废话)据说,如果至少满足了以下三个条件之一,公司A就可以控制公司B了: 公司A = 公司B. 公司A拥 ...
- bzoj 5248: [2018多省省队联测]一双木棋
Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何棋子, 两人轮流在格子上落子,直到填满棋盘时结束.落子的规则是:一个格子可以落子 ...
- [luoguP3729]曼哈顿计划EX
来自FallDream的博客,未经允许,请勿转载,谢谢. 艾登拥有一个计算机网络,每一台计算机都至少有着Intel Xeon E50 v40 + 40路GTX10800Titan的恐怖配置,并由无线网 ...
- CCA更新流程分析
1 CCA CCA(空间信道评估)在CSMA/CA中比较非常重要,事关整机吞吐量,所以对其实现进行简单分析.CCA好像应该有2种:CCA-CS,是属于PLCP层的,捕获到能量且能量值高于-82dB后, ...
- java开发笔记
replace与replaceAll的区别 replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换(CharSequence即字符串序列的意思,说白了也就是 ...
- python正则表达式与Re库
正则表达式是用来简洁表达一组字符串的表达式,一行胜千言,有点类似于数列的通项公式. 在python中提供了re库(regular expression)即正则表达式库,内置于python的标准库中,导 ...
- 计科1702冯亚杰C语言程序设计预备作业
阅读邹欣老师的博客--师生关系,针对文中的几种师生关系谈谈你的看法,你期望的师生关系是什么样的? 答:首先老师和学生之间要互相尊重,我认为这是必要的.在第一点的基础上师生要互相帮助,互相配合,共同进步 ...
- Java并发编程之并发工具类
CountDownLatch CountDownLatch可以用于一个或多个线程等待其他线程完成操作. 示例代码 private static CountDownLatch c = new Count ...