前言:这两天学习了代理模式,自然想到了 springmvc 的 aop 使用的就是动态代理,拦截器使用的就是 jdk 的动态代理。今天看了看源码,记录一下。转载请注明出处:https://www.cnblogs.com/yuxiaole/p/9969360.html

springMVC 的拦截器使用移步:Java Servlet 过滤器与 springmvc 拦截器的区别?

源码解析

  springMVC 的所有连接入口都会进入 DispatcherServlet,然后在这里面去调用真正的 Controller。而拦截器要达到的作用则是在调用 Controller 前后去做一些事情。所以现在需要看看 DispatcherServlet 的源码。

DispatcherServlet

  DispatcherServlet 的源码入口在 doService() 方法。

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if(this.logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult()?" resumed":"";
this.logger.debug("DispatcherServlet with name '" + this.getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
} Map<String, Object> attributesSnapshot = null;
if(WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration attrNames = request.getAttributeNames(); label108:
while(true) {
String attrName;
do {
if(!attrNames.hasMoreElements()) {
break label108;
} attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet")); attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
} request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if(inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
} request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try {
this.doDispatch(request, response);
} finally {
if(!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
} } }

  doService() 方法里面处理了一些信息之后,调用了 doDispatch() 方法。

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try {
try {
ModelAndView mv = null;
Object dispatchException = null; try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if(mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
} HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if(isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if(this.logger.isDebugEnabled()) {
this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
} if((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
} if(!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
} mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if(asyncManager.isConcurrentHandlingStarted()) {
return;
} this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
} this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
} } finally {
if(asyncManager.isConcurrentHandlingStarted()) {
if(mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if(multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
} }
}

  doDispatch() 方法中通过 this.getHandler(processedRequest); 获取到了处理器链 HandlerExecutionChain mappedHandle 之后,去执行了  mappedHandler.applyPreHandle(processedRequest, response) 方法,从而执行了拦截器的 preHandle 方法,如果返回为 false,则会调用处理器链的 triggerAfterCompletion 方法,然后 DispatchServlet 类中会直接 retreturn;如果返回为 true,则继续。

  然后调用了 HandlerAdapter 的 handler() 方法;

  然后调用了 mappedHandler.applyPostHandle(processedRequest, response, mv); 方法,从而执行了拦截器的 postHandle 方法;

  然后调用了 this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); 方法;在 processDispatchResult() 方法里面渲染了对应的视图,然后调用了 mappedHandler.triggerAfterCompletion(request, response, (Exception)null); 方法,从而执行了拦截器的 afterCompletion 方法。

  processDispatchResult() 源码如下:

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if(exception != null) {
if(exception instanceof ModelAndViewDefiningException) {
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else {
Object handler = mappedHandler != null?mappedHandler.getHandler():null;
mv = this.processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
} if(mv != null && !mv.wasCleared()) {
this.render(mv, request, response);
if(errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if(this.logger.isDebugEnabled()) {
this.logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + this.getServletName() + "': assuming HandlerAdapter completed request handling");
} if(!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if(mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
} }
}

  从 doDispatch() 方法这里主要需要知道 HandlerExecutionChain mappedHandler = this.getHandler(processedRequest); 这一句调用的 getHandler() 方法,源码如下。

  getHandle() 方法里是通过 HandlerMapping 的 getHandler 方法返回 HandlerExecutionChain 的。

  从代码中不难看出整个逻辑就是依次判断 servlet 中的每个 handlerMapping 是否能够匹配该请求,直到找到那个匹配的然后返回处理结果。

    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Iterator var2 = this.handlerMappings.iterator(); HandlerExecutionChain handler;
do {
if(!var2.hasNext()) {
return null;
} HandlerMapping hm = (HandlerMapping)var2.next();
if(this.logger.isTraceEnabled()) {
this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'");
} handler = hm.getHandler(request);
} while(handler == null); return handler;
}

HandlerExecutionChain 类

  applyPreHandle() 方法源码如下:可以看出是顺序调用拦截器的 preHandle() 方法。preHandle 返回 false 时调用了 triggerAfterCompletion 方法。

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if(!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
if(!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
} return true;
}

  applyPostHandle() 方法源码如下:可以看出这里是逆序调用 postHandle 方法。

    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = this.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);
}
} }

 triggerAfterCompletion() 方法源码如下:可以看出这里也是逆序调用 afterCompletion 方法。

    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
HandlerInterceptor[] interceptors = this.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);
} catch (Throwable var8) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
}
}
} }

  

转载请注明出处:https://www.cnblogs.com/yuxiaole/p/9969360.html

springMVC 拦截器源码解析的更多相关文章

  1. Struts2 源码分析-----拦截器源码解析 --- ParametersInterceptor

    ParametersInterceptor拦截器其主要功能是把ActionContext中的请求参数设置到ValueStack中,如果栈顶是当前Action则把请求参数设置到了Action中,如果栈顶 ...

  2. struts2拦截器源码分析

    前面博客我们介绍了开发struts2应用程序的基本流程(开发一个struts2的实例),通过前面我们知道了struts2实现请求转发和配置文件加载都是拦截器进行的操作,这也就是为什么我们要在web.x ...

  3. Jfinal拦截器源码解读

    本文对Jfinal拦截器源码做以下分析说明

  4. 0002 - Spring MVC 拦截器源码简析:拦截器加载与执行

    1.概述 Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理.例如通过拦截器可以进行权限验证.记录请求信息的日 ...

  5. RestFramework之序列化器源码解析

    一.源码解析之序列化: 1.当视图类进行实例化序列化类做了如下操作: #ModelSerializer继承Serializer再继承BaseSerializer(此类定义实例化方法) #在BaseSe ...

  6. DRF之解析器源码解析

    解析器 RESTful一种API的命名风格,主要因为前后端分离开发出现前后端分离: 用户访问静态文件的服务器,数据全部由ajax请求给到 解析器的作用就是服务端接收客户端传过来的数据,把数据解析成自己 ...

  7. 复习整理9:SpringMVC应用以及源码解析

    一:SpringMVC是什么 SpringMVC只是Spring的一个子框架,作用学过Struts2的应该很好理解,他们都是MVC的框架.学他就是用来代替Struts2的,那么为什么不用Struts2 ...

  8. OkHttp3 拦截器源码分析

    OkHttp 拦截器流程源码分析 在这篇博客 OkHttp3 拦截器(Interceptor) ,我们已经介绍了拦截器的作用,拦截器是 OkHttp 提供的对 Http 请求和响应进行统一处理的强大机 ...

  9. 关于阅读Struts2部分拦截器源码的记录

    Struts2中的拦截器在ActionInvocation对象的invoke()方法中执行. ActionInvocation对象从配置文件中读取Interceptor对象,加入到自己的存取拦截器的容 ...

随机推荐

  1. noip第17课资料

  2. Python序列结构--列表(一)

    列表 列表**包含若干元素的有序连续内存空间**,当列表增加或删除元素时,**列表对象自动进行内存的扩展或收缩**,从而**保证相邻元素之间没有缝隙**.但插入和删除非尾部元素时涉及列表元素大量的移动 ...

  3. Dynamic Programming | Set 4 (Longest Common Subsequence)

    首先来看什么是最长公共子序列:给定两个序列,找到两个序列中均存在的最长公共子序列的长度.子序列需要以相关的顺序呈现,但不必连续.例如,"abc", "abg", ...

  4. SQL Server 最大并行度

    一.概念 1.关联掩码(affinitymask) 为了执行多任务,MicrosoftWindows2000和WindowsServer2003有时会在不同的处理器之间移动进程线程.虽然从操作系统方面 ...

  5. redis 实现发布订阅的功能

    redis 除了作为缓存的功能外还可以用作消息中间件的功能,这片博客主要是介绍一下 redis 整合spring 实现消息的发布和订阅功能: 1:redis依赖,依赖两个包,redis 包, spri ...

  6. 用O(1)的时间复杂度删除单链表中的某个节点

    给定链表的头指针和一个结点指针,在O(1)时间删除该结点.链表结点的定义如下: struct ListNode { int m_nKey; ListNode* m_pNext; }; 函数的声明如下: ...

  7. Linux shell逐行读取文件的方法

    方法1:while循环中执行效率最高,最常用的方法. function while_read_line_bottom(){ while read line do echo $line done < ...

  8. SOA总结(脑图图片)

  9. CentOS 安装 kafka

    首先确保JDK已正确安装并设置好环境变量 安装Zookeeper 到官网下载: https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/ zooke ...

  10. Android应用系列:值得收藏的ViewHolder工具类实现

    前言 在开发APP的过程中,攻城狮少不了要跟ListView.GridView这些组件眉来眼去,暗送几波秋波.自然原生态美人BaseAdapter更是程序员的最爱,有了它,我们想怎么干就能怎么干,嘿嘿 ...