springMVC 拦截器源码解析
前言:这两天学习了代理模式,自然想到了 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 拦截器源码解析的更多相关文章
- Struts2 源码分析-----拦截器源码解析 --- ParametersInterceptor
ParametersInterceptor拦截器其主要功能是把ActionContext中的请求参数设置到ValueStack中,如果栈顶是当前Action则把请求参数设置到了Action中,如果栈顶 ...
- struts2拦截器源码分析
前面博客我们介绍了开发struts2应用程序的基本流程(开发一个struts2的实例),通过前面我们知道了struts2实现请求转发和配置文件加载都是拦截器进行的操作,这也就是为什么我们要在web.x ...
- Jfinal拦截器源码解读
本文对Jfinal拦截器源码做以下分析说明
- 0002 - Spring MVC 拦截器源码简析:拦截器加载与执行
1.概述 Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理.例如通过拦截器可以进行权限验证.记录请求信息的日 ...
- RestFramework之序列化器源码解析
一.源码解析之序列化: 1.当视图类进行实例化序列化类做了如下操作: #ModelSerializer继承Serializer再继承BaseSerializer(此类定义实例化方法) #在BaseSe ...
- DRF之解析器源码解析
解析器 RESTful一种API的命名风格,主要因为前后端分离开发出现前后端分离: 用户访问静态文件的服务器,数据全部由ajax请求给到 解析器的作用就是服务端接收客户端传过来的数据,把数据解析成自己 ...
- 复习整理9:SpringMVC应用以及源码解析
一:SpringMVC是什么 SpringMVC只是Spring的一个子框架,作用学过Struts2的应该很好理解,他们都是MVC的框架.学他就是用来代替Struts2的,那么为什么不用Struts2 ...
- OkHttp3 拦截器源码分析
OkHttp 拦截器流程源码分析 在这篇博客 OkHttp3 拦截器(Interceptor) ,我们已经介绍了拦截器的作用,拦截器是 OkHttp 提供的对 Http 请求和响应进行统一处理的强大机 ...
- 关于阅读Struts2部分拦截器源码的记录
Struts2中的拦截器在ActionInvocation对象的invoke()方法中执行. ActionInvocation对象从配置文件中读取Interceptor对象,加入到自己的存取拦截器的容 ...
随机推荐
- ModelAndView对象
ModelAndView属性中两个最重要的属性是model和view. view即视图,保存的是视图信息. model即模型,以<K,V>形式保存模型数据,上图可以看到是MdelMap类型 ...
- Beta冲刺 (5/7)
Part.1 开篇 队名:彳艮彳亍团队 组长博客:戳我进入 作业博客:班级博客本次作业的链接 Part.2 成员汇报 组员1(组长)柯奇豪 过去两天完成了哪些任务 共享编辑文章的后端数据处理 部分代码 ...
- 1.Spring框架入门案例
一.简单入门案例 入门案例:IoC 1.项目创建与结构 2.接口与实现类 User.java接口 package com.jd.ioc; /** * @author weihu * @date 201 ...
- iOS 系统通知
iOS相当多一部分系统事件实际上都是通过通知来完成的,依赖于通知的广播形式,我们可以在AppDelegate中通过添加空通知来捕捉所有通知: static NSString *const MYNOTI ...
- 使用ILMerge 打包C# 绿色免安装版程序
使用ILMerge工具,将C#项目debug目录下的exe及其依赖的dll文件打包成一个exe文件,直接双击就可运行. 使用工具: ILMerge :http://www.microsoft.com/ ...
- PHP合并数组
1.arrary_merge 示例代码: $arr1 = array(1, 2, 3, 4, 5); $arr2 = array(1, 2, 6, 7, 8, 9, 10); $result1 = a ...
- Java面试集合(三)
前言 大家好,给大家带来Java面试集合(三)的概述,希望你们喜欢 三 1.在Java中是否可以含有多个类? 答:可以含有多个类,但只有一个是public类,public类的类名与文件名必须一致. 2 ...
- celery异步认知
celery是异步任务的框架 是由python实现的异步框架. 在使用celery我们经常分为三个部分, 第一部分就是我们所说的客户端, 就是发起异步任务的一方, 第二部分 任务队列 broker 第 ...
- Java 8 停止维护,Java 9 难产,IDEA 2018 发布,还有……
祝大家五一劳动节快乐,工作顺利! 又到了总结上个月干货的时候了,这个月我们带来了各种Java技术干货,各种送书抽奖福利,各种面试题分享,各种最新动态资讯等. 5.1重磅活动 | 区块链免费送书 &am ...
- java main()线程是不是最后一个退出的(相比较main中创建的其他多个线程)
JVM会在所有的非守护线程(用户线程)执行完毕后退出: main线程是用户线程: 仅有main线程一个用户线程执行完毕,不能决定JVM是否退出,也即是说main线程并不一定是最后一个退出的线程. pu ...