SpringMVC源码阅读:拦截器

1.前言SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧本文将通过源码(基于Spring4.3.7)分析,弄清楚SpringMVC拦截器的工作原理2.源码分析进入SpringMVC核心类DispatcherServlet的doDispatch方法,在SpringMVC源码阅读:核心分发器Di...

SpringMVC源码阅读:拦截器

1.前言

SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧

本文将通过源码(基于Spring4.3.7)分析,弄清楚SpringMVC拦截器的工作原理

2.源码分析

进入SpringMVC核心类DispatcherServlet的doDispatch方法,在SpringMVC源码阅读:核心分发器DispatcherServlet曾经分析过,这里再分析一遍

936行获得HandlerExecutionChain,含有HandlerMethod和interceptorList

943行根据HandlerExecutionChain获取RequestMappingHandlerAdapter

958行如果HandlerExecutionChain需要执行下一个拦截器,则返回True

963HandlerAdapter调用Handler处理请求,可以看到,请求方法夹在applyPreHandleapplyPostHandle之间

980行processDispatchResult会调用triggerAfterCompletion,不抛出异常

983和986行调用triggerAfterCompletion会抛出异常

重点看下936行getHandler方法,点进去

1156行HandlerMapping调用getHandler方法获取HandlerExecutionChain

对着getHandler ctrl alt b跳转到HandlerMapping接口方法实现处,在AbstractHandlerMapping类中

352行获取HandlerMethod

365行获取HandlerExecutionChain

366行对跨域请求进行拦截处理

点进去365行的getHandlerExecutionChain方法

417行获取requestmapping请求路径

419行判断HandlerInterceptor是不是MappedInterceptor类型,不是则直接向HandlerExecutionChain加入HandlerInterceptor

HandlerInterceptor是MappedInterceptor类型,需要检验是否匹配,最后向HandlerExecutionChain加入HandlerInterceptor

getCorsHandlerExecutionChain方法获取跨域的HandlerExecutionChain和getHandlerExecutionChain同理,园友可自行分析

现在看看HandlerExecutionChain

主要看applyPostHandle、applyPreHandle和triggerAfterCompletion方法

打开applyPostHandle方法

130行接收HandlerInterceptor数组

134行HandlerInterceptor的preHandle方法执行失败依然会执行HandlerExecutionChain的triggerAfterCompletion方法

triggerAfterCompletion方法在所有拦截器preHandle方法成功执行返回True后才会执行(触发afterCompletion)

3.实例

设置自定义拦截器,继承HandlerInterceptorAdapter

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/login");  return false; }}

测试Controller

@Controller@RequestMapping(value = "/login")public class LoginController { //@RequestMapping(value = {"/", ""}) @RequestMapping(value = {"login"}) @ResponseBody public String login() {  return "login"; } @RequestMapping("/auth") public String auth(@RequestParam String username, HttpServletRequest req) {  req.getSession().setAttribute("loginUser", username);  return "redirect:/"; } @RequestMapping("/out") public String out(HttpServletRequest req) {  req.getSession().removeAttribute("loginUser");  return "redirect:/login/login"; }}

在dispatcher-servlet.xml配置拦截器

因为我们使用了<mvc:annotation-driven/>注解,SpringMVC源码阅读:Json,Xml自动转换提到过

<mvc:annotation-driven/>自动帮我们注册了

  1. RequestMappingHandlerMapping
  2. RequestMappingHandlerAdapter
  3. ExceptionHandlerExceptionResolver

所以只要在RequestMappingHandlerMapping中配置interceptors属性

interceptors属性来自于RequestMappingHandlerMapping的父类AbstractHandlerMapping

 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">  <property name="interceptors"><bean class="org.format.demo.interceptor.LoginInterceptor"/>  </property> </bean>

现在浏览器输入任何路径,都会跳转到http://localhost:8080/springmvcdemo/login/login,说明拦截器已经生效

浏览器输入http://localhost:8080/springmvcdemo/login/auth?username=ss,给HttpSession设置Attribute,返回主界面

浏览器输入http://localhost:8080/springmvcdemo/login/out,将HttpSession的Attribute移除,重定向到http://host:port/contextPath/login/login

我们还可以通过<mvc:interceptors>

源文地址:https://www.guoxiongfei.cn/cntech/9692.html