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对象,加入到自己的存取拦截器的容 ...
随机推荐
- 深入理解Java虚拟机二之Java内存区域与内存溢出异常
运行时数据区域 1.线程独有的内存区域 PROGRAM COUNTER REGISTER 程序计数器 程序计数器空间较小,是当前线程执行字节码的行号指示器,字节码解释器工作时就是通过改变这个计数器的值 ...
- hiho 第六周 01背包
简单的01背包,没有报名,这周的没有权限提交 #include<iostream> #include<memory.h> using namespace std; #defin ...
- Android框架式编程之MVP架构
MVP(Model-View-Presenter)模式.是将APP的结构分为三层:View - Presenter - Model. View 1. 提供UI交互 2. 在presenter的控制下修 ...
- i==1 && resolve()
for( var i=100000 ; i>0 ; i-- ){ i==1 && resolve() } var dd = 988889;console.log(`${dd}`) ...
- Java学习笔记37(字节流)
输出:程序到文件 输入:文件到程序 字节输出流:OutputStream类 作用:在java程序中写文件 这个类是抽象类,必须使用它的子类 方法: 写入: package demo; import j ...
- XStream进行xml和bean互转
加入pom <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>x ...
- Liferay7 BPM门户开发之8: Activiti实用问题集合
1.如何实现审核的上级获取(任务逐级审批) 这个是必备功能,通过Spring的注入+Activiti表达式可以很容易解决. 可参考: http://blog.csdn.net/sunxing007/a ...
- postgresql-磁盘空间不足问题排查
问题背景 加压测试过程中发现插入数据过程中报错:could not write to hash-join temporary file: 设备上没有空间.但是查看服务器还有很多空闲空间,是什么导致这样 ...
- TypeEncodings
官网链接: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Ar ...
- web自动化测试(java)---测试过程中遇到的错误合集
摸索测试,不管是安装.调测第一个用例都会遇到各种各样的问题,或是自己的问题或是程序本身设置问题 只有把所有问题记录下来,才对得起自己的经历 1.设置firefox的执行文件错误 Exception i ...