拦截器是每个Web框架必备的功能,也是个老生常谈的主题了。本文将分析SpringMVC的拦截器功能是如何设计的,让读者了解该功能设计的原理。

重要接口及类介绍1. HandlerExecutionChain类由HandlerMethod和Interceptor集合组成的类,会被HandlerMapping接口的getHandler方法获取。2. HandlerInterceptor接口SpringMVC拦截器基础接口。3. AbstractHandlerMappingHandlerMapping的基础抽象类。4. AsyncHandlerInterceptor继承HandlerInterceptor的接口,额外提供了afterConcurrentHandlingStarted方法,该方法是用来处理异步请求。当Controller中有异步请求方法的时候会触发该方法。楼主做过测试,异步请求先支持preHandle、然后执行afterConcurrentHandlingStarted。异步线程完成之后执行preHandle、postHandle、afterCompletion。有兴趣的读者可自行研究。5. HandlerInterceptorAdapter实现AsyncHandlerInterceptor接口的抽象类,一般我们使用拦截器的话都会继承这个类。然后复写相应的方法。6. WebRequestInterceptor与HandlerInterceptor接口类似,区别是WebRequestInterceptor的preHandle没有返回值。还有WebRequestInterceptor是针对请求的,接口方法参数中没有response。AbstractHandlerMapping内部的interceptors是个Object类型集合。处理的时候判断为MappedInterceptor[加入到mappedInterceptors集合中];HandlerInterceptor、WebRequestInterceptor(适配成WebRequestHandlerInterceptorAdapter)[加入到adaptedInterceptors中]7. MappedInterceptor一个包括includePatterns和excludePatterns字符串集合并带有HandlerInterceptor的类。很明显,就是对于某些地址做特殊包括和排除的拦截器。8. ConversionServiceExposingInterceptor默认的标签初始化的时候会初始化ConversionServiceExposingInterceptor这个拦截器,并被当做构造方法的参数来构造MappedInterceptor。之后会被加入到AbstractHandlerMapping的mappedInterceptors集合中。该拦截器会在每个请求之前往request中丢入ConversionService。主要用于spring:eval标签的使用。

源码分析首先我们看下拦截器的如何被调用的。Web请求被DispatcherServlet截获后,会调用DispatcherServlet的doDispatcher方法。很明显地看到,在HandlerAdapter处理之后,以及处理完成之后会调用HandlerExecutionChain的方法。HandlerExecutionChain的applyPreHandle、applyPostHandle、triggerAfterCompletion方法如下:很明显,就是调用内部实现HandlerInterceptor该接口集合的各个对应方法。下面我们看下HandlerExecutionChain的构造过程。HandlerExecutionChain是从HandlerMapping接口的getHandler方法获取的。HandlerMapping的基础抽象类AbstractHandlerMapping中:我们看到,HandlerExecutionChain的拦截器是从AbstractHandlerMapping中的adaptedInterceptors和mappedInterceptors属性中获取的。

拦截器的配置清楚了HandlerExecutionChain的拦截器属性如何构造之后,下面来看下SpringMVC是如何配置拦截器的。1. *-dispatcher.xml配置文件中添加 配置

这里配置的每个都会被解析成MappedInterceptor。其中子标签会被解析成MappedInterceptor的includePatterns属性;会被解析成MappedInterceptor的excludePatterns属性;会被解析成MappedInterceptor的interceptor属性。这个标签是被InterceptorsBeanDefinitionParser类解析。2. 配置RequestMappingHandlerMapping,并配置该bean对应的interceptors集合属性。这里的interceptors集合是个Object类型的泛型集合。AbstractHandlerMapping抽象类只暴露了1个拦截器的set方法 -> interceptors。adaptedInterceptors和mappedInterceptors均没有暴露set方法,因此我们只能为RequestMappingHandlerMapping配置interceptors属性。其实AbstractHandlerMapping内部的initInterceptors方法中,会遍历interceptors集合,然后判断各个项是否是MappedInterceptor、HandlerInterceptor、WebRequestInterceptor。其中MappedInterceptor类型的拦截器会被加到mappedInterceptors集合中,HandlerInterceptor类型的会被加到adaptedInterceptors集合中,WebRequestInterceptor类型的会被适配成WebRequestHandlerInterceptorAdapter加到adaptedInterceptors集合中。如果读者配置了:那么配置如下:

否则,可以去掉order这个属性的设置。

一般建议使用第一种方法。

编写自定义的拦截器public class LoginInterceptor extends HandlerInterceptorAdapter {

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response,

Object handler) throws Exception {

// 获得请求路径的uri

String uri = request.getRequestURI();

// 判断路径是登出还是登录验证,是这两者之一的话执行Controller中定义的方法

if(uri.endsWith("/login/auth") || uri.endsWith("/login/out")) {

return true;

}

// 进入登录页面,判断session中是否有key,有的话重定向到首页,否则进入登录界面

if(uri.endsWith("/login/") || uri.endsWith("/login")) {

if(request.getSession() != null && request.getSession().getAttribute("loginUser") != null) {

response.sendRedirect(request.getContextPath() + "/index");

} else {

return true;

}

}

// 其他情况判断session中是否有key,有的话继续用户的操作

if(request.getSession() != null && request.getSession().getAttribute("loginUser") != null) {

return true;

}

// 最后的情况就是进入登录页面

response.sendRedirect(request.getContextPath() + "/login");

return false;

}

}登录Controller:@Controller

@RequestMapping(value = "/login")

public class LoginController {

@RequestMapping(value = {"/", ""})

public String index() {

return "login";

}

@RequestMapping("/auth")

public String auth(@RequestParam String username, HttpServletRequest req) {

req.getSession().setAttribute("loginUser", username);

return "redirect:/index";

}

@RequestMapping("/out")

public String out(HttpServletRequest req) {

req.getSession().removeAttribute("loginUser");

return "redirect:/login";

}

}*-diapatcher.xml配置:

PS:我们看到LoginInterceptor里的preHandle方法对于地址“/login/auth”和"/login/out"不处理。因此,可以写点配置,少写带java代码。在拦截器配置中添加2个exclude-mapping,并且去掉LoginInterceptor里的if(uri.endsWith("/login/auth") || uri.endsWith("/login/out")) {

return true;

}

配置新增:

总结总结了SpringMVC拦截器的原理以及各种配置,像网上很多人会问为什么拦截器执行preHandle方法返回false之后还是会执行afterCompletion方法,其实我们看下源码就知道了。关于异步请求方面的拦截器以及第二种配置方法(interceptors集合属性可加入继承自HandlerInterceptorAdapter抽象类的类以及实现WebRequestInterceptor接口的类),读者可自行研究。

java面试 拦截器问题_面试必问:给我说一下Spring MVC拦截器的原理?相关推荐

  1. 【Java Web开发学习】Spring MVC 拦截器HandlerInterceptor

    [Java Web开发学习]Spring MVC 拦截器HandlerInterceptor 转载:https://www.cnblogs.com/yangchongxing/p/9324119.ht ...

  2. Java Spring MVC框架 VIII 之 Spring MVC拦截器

    Java Spring MVC框架 VIII 之 Spring MVC拦截器 Spring MVC拦截器 1.拦截器简介 拦截器是SpringMvc框架提供的功能 它可以在控制器方法运行之前或运行之后 ...

  3. 使用session监听+spring MVC拦截器禁止用户重复登录

    在许多web项目中,需要禁止用户重复登录.一般来说有两种做法: 一是在用户表中维护一个字段isOnLine(是否在线),用户登录时,设定值为true,用户退出时设定为false,在重复登录时,检索到该 ...

  4. spring mvc拦截器_Spring MVC拦截器示例

    spring mvc拦截器 我认为现在是时候看看Spring的MVC拦截器机制了,这种机制已经存在了很多年,并且是一个非常有用的工具. Spring Interceptor会按照提示说:在传入的HTT ...

  5. Spring MVC拦截器~~~登陆验证拦截

    [ 30 分 钟 轻 松 入 门 Spring MVC][web 三 大 组 件 之 ~ ~ Filter 过 滤 器] Interceptor 拦截器学习: 1.了解spring mvc拦截器的概念 ...

  6. spring mvc 拦截器拦截jsp页面

    spring mvc 拦截器怎么拦截jsp页面 你这个 是拦截带 /jsp 的 .do请求 解决方案 用spring 的拦截器 去拦截 所有的 .do 请求, 然后写一个 过滤器去拦截 所有的.jsp ...

  7. [Spring mvc 深度解析(三)] 创建Spring MVC之器

    第9章 创建Spring MVC之器 ​ 本章将分析Spring MVC自身的创建过程.首先分析Spring MVC的整体结构,然后具体分析每一层的创建过程. 1 整体结构介绍 Spring MVC中 ...

  8. Spring MVC验证器:Validator接口和ValidationUtils类

    本节主要介绍创建自定义 Spring 验证器时需要实现的 Validator 接口和工具类 ValidationUtils. Validator接口 创建自定义 Spring 验证器需要实现 org. ...

  9. java tcp 阻塞等待应答_面试常问!TCP 的三次握手与四次挥手理解

    来源:青柚_ blog.csdn.net/qq_38950316/article/details/81087809 三次握手过程理解 四次挥手过程理解 常见面试题 先来张图! 序列号seq: 占4个字 ...

  10. Spring MVC拦截器实现

    到这段时, 想起来了以前学底层一些的servlet & jsp技术时, 过滤器和拦截器也有相关实现, 但比起来,spring的实现,可用性高很多. 其它代码不再放上来, 只放拦截器实现和xml ...

最新文章

  1. Target runtime Apache Tomcat v7.0 is not defined.
  2. 基本电路元件和特性(1)电阻基础(R)
  3. QEMU虚拟网卡设备的创建流程
  4. struts2 spring jfreechart 整合
  5. 计算机网络【10】—— Cookie与Session
  6. MVVM架构~knockoutjs系列之验证成功提示显示
  7. JavaScript实现k-Means算法(附完整源码)
  8. SAP UI5不支持delta render
  9. JPA分页查询与条件分页查询
  10. Python 之 获取Host Esxi 主机信息
  11. VB编程必备!_VB源码之友(内含-下载-破解-使用方法)
  12. 使用UE4基于Hololens开发MR应用
  13. ApacheCN 编程/大数据/数据科学/人工智能学习资源 2019.12
  14. 计算机网络基础与应用复习提纲,计算机网络及应用期末复习提纲
  15. Scons安装和使用
  16. 《JAVA设计模式系列》责任链模式
  17. OpenCV中文文档
  18. yuv 10bit 8bit
  19. google 广告条代码
  20. Hotspot细节实现安全区域、记忆集卡表

热门文章

  1. C# C++ Java
  2. java 数值区间_java 各数据类型数值范围
  3. 创建windows窗口并且获得窗口句柄
  4. 【matlab】pcolor和colormap的使用
  5. perf报错解决:no symbols found in /bin/dash, maybe install a debug package?和was updated (is prelink enabl
  6. 解决Linux最大进程数和最大文件句柄问题
  7. 打造自己的树莓派监控系统3--canvas.js绘制数据
  8. Apache软件历史版本下载地址
  9. 计算机系统上线保障计划,系统运维信息系统运行保障方案计划新.docx
  10. android os被删除怎么办,手机系统应用误删了怎么办 如何修复手机异常【详细介绍】...