springboot-拦截器的实现、执行时机及原理
目录
一、登录拦截器使用
1.编写一个拦截器实现HandlerInterceptor接口
2、拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)
3、指定拦截规则【如果是拦截所有,静态资源也会被拦截】
二、拦截器的实现原理
1.springmvc处理逻辑参考博文
2.DispatcherServlet的doDispatch方法
3.执行拦截器的preHandle方法
4.倒叙执行所有拦截器的postHandle方法
5.页面成功渲染完成以后触发 afterCompletion
6.总结
一、登录拦截器使用
1.编写一个拦截器实现HandlerInterceptor接口
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/**
* 登录检查拦截器
* 1、配置好拦截器要拦截哪些请求
* 2、把这些配置放在容器中
*/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {/*** 目标方法执行之前执行*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String requestURI = request.getRequestURI();log.info("preHandle拦截的请求路径是{}",requestURI);//登录检查逻辑HttpSession session = request.getSession();Object loginUser = session.getAttribute("loginUser");if(loginUser != null){//返回true就是 放行return true;}//拦截住。未登录。跳转到登录页request.setAttribute("msg","请先登录");//response.sendRedirect("/"); // 重定向(重定向无法传递数据)request.getRequestDispatcher("/").forward(request,response);// 转发可以传递参数return false;}/*** 目标方法执行完成以后,还未到页面渲染*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("postHandle执行{}",modelAndView);}/*** 页面渲染以后执行,或者方法执行失败执行*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("afterCompletion执行异常{}",ex);}
}
2、拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") //所有请求都被拦截包括静态资源.excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**"); //放行的请求}
}
3、指定拦截规则【如果是拦截所有,静态资源也会被拦截】
如第2步,加上拦截的资源和放行的请求。
二、拦截器的实现原理
1.springmvc处理逻辑参考博文
springBoot-springMVC请求处理原理_私人博客,有需要请联系17854238061(vx同号)-CSDN博客
springmvc响应json与xml原理-详解数据响应与内容协商:
springboot-springmvc响应json与xml原理-详解数据响应与内容协商(长文预警,收藏慢啃)_私人博客,有需要请联系17854238061(vx同号)-CSDN博客
2.DispatcherServlet的doDispatch方法
DispatcherServlet的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 {ModelAndView mv = null;Exception dispatchException = null;try {processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// Determine handler for the current request.// 拿到请求处理器,里面有拦截器的数组HandlerInterceptor[]// 根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}// Determine handler adapter for the current request.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// Process last-modified header, if supported by the handler.String method = request.getMethod();boolean isGet = "GET".equals(method);if (isGet || "HEAD".equals(method)) {long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}// 目标方法执行之前,会执行该方法// 遍历所有拦截器,执行拦截器的preHandle方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {// 如果任何一个拦截器返回false。直接跳出不执行目标方法。return;}// 执行目标方法// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);// 倒叙执行所有拦截器的postHandle方法mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {// As of 4.3, we're processing Errors thrown from handler methods as well,// making them available for @ExceptionHandler methods and other scenarios.dispatchException = new NestedServletException("Handler dispatch failed", err);}// 该方法是页面渲染逻辑,页面成功渲染完成以后,也会倒序触发 afterCompletionprocessDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {// 前面的步骤有任何异常也都会直接倒序触发 afterCompletion// 一切正常也会触发afterCompletiontriggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) {// 前面的步骤有任何异常也都会直接倒序触发 afterCompletion// 一切正常也会触发afterCompletiontriggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err));}finally {if (asyncManager.isConcurrentHandlingStarted()) {// Instead of postHandle and afterCompletionif (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}
}
请求处理器,里面有拦截器的数组HandlerInterceptor[]
3.执行拦截器的preHandle方法
先来顺序执行 所有拦截器的 preHandle方法
① 如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle方法。
② 如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion方法。
如果任何一个拦截器返回false。直接跳出不执行目标方法。
// org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for (int i = 0; i < interceptors.length; i++) {HandlerInterceptor interceptor = interceptors[i];if (!interceptor.preHandle(request, response, this.handler)) {triggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i;}}return true;
}
// org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)throws Exception {HandlerInterceptor[] interceptors = 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 ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);}}}
}
4.倒叙执行所有拦截器的postHandle方法
// org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)throws Exception {HandlerInterceptor[] interceptors = 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);}}
}
5.页面成功渲染完成以后触发 afterCompletion
// org.springframework.web.servlet.DispatcherServlet#processDispatchResult
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {boolean errorView = false;if (exception != null) {if (exception instanceof ModelAndViewDefiningException) {logger.debug("ModelAndViewDefiningException encountered", exception);mv = ((ModelAndViewDefiningException) exception).getModelAndView();}else {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);mv = processHandlerException(request, response, handler, exception);errorView = (mv != null);}}// Did the handler return a view to render?if (mv != null && !mv.wasCleared()) {render(mv, request, response);if (errorView) {WebUtils.clearErrorRequestAttributes(request);}}else {if (logger.isTraceEnabled()) {logger.trace("No view rendering, null ModelAndView returned.");}}if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {// Concurrent handling started during a forwardreturn;}if (mappedHandler != null) {// Exception (if any) is already handled..// 页面成功渲染完成以后触发 afterCompletionmappedHandler.triggerAfterCompletion(request, response, null);}
}
页面成功渲染完成以后,也会倒序触发 afterCompletion
// org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)throws Exception {HandlerInterceptor[] interceptors = 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 ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);}}}
}
6.总结
1、根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】
2、先来顺序执行 所有拦截器的 preHandle方法
(1)、如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle
(2)、如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion;
3、如果任何一个拦截器返回false。直接跳出不执行目标方法
4、所有拦截器都返回True。则继续执行目标方法
5、目标方法执行完成之后,倒序执行所有拦截器的postHandle方法。
6、前面的步骤有任何异常都会直接倒序触发 afterCompletion
7、页面成功渲染完成以后,也会倒序触发 afterCompletion
springboot-拦截器的实现、执行时机及原理相关推荐
- SpringBoot 拦截器 过滤器
1.过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的.请求结束返回也是,是在servlet处理完后,返回给前端之前. 2.拦截器可以获取IOC容器中的各 ...
- springboot拦截器 跳过_springboot创建拦截器过程图解
springboot创建拦截器过程图解 这篇文章主要介绍了springboot创建拦截器过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一. ...
- Spring AOP 源码分析 - 拦截器链的执行过程
1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...
- 【SpringBoot】SpringBoot拦截器实战和 Servlet3.0自定义Filter、Listener
=================6.SpringBoot拦截器实战和 Servlet3.0自定义Filter.Listener ============ 1.深入SpringBoot2.x过滤器Fi ...
- SpringBoot拦截器与过滤器
一.拦截器与过滤器 在讲Spring boot之前,我们先了解一下过滤器和拦截器.这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的.在分析两者的区别之前,我们先理解一下AOP的概念,A ...
- springboot拦截器与过滤器详解
前言 不管是传统的ssm项目,还是springboot项目,拦截器和过滤器在项目开发中都离不开,比如说对于ssm框架类的项目来说,许多登录逻辑的前置校验,黑白名单的检查,以及部分请求的数据分析等依然需 ...
- springboot文件上传和下载工具_SpringBoot图文教程7—SpringBoot拦截器的使用姿势这都有...
有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...
- SpringBoot拦截器配置
SpringBoot拦截器配置 自定义拦截器: com.example.mybatis2018.interceptor.MyInterCeptor package com.example.mybati ...
- Springboot 拦截器链 - 加载拦截器
Springboot 拦截器链 - 加载拦截器 1.创建拦截器 // 创建拦截器需要实现 HandlerInterceptor 接口 @Slf4j public class HandleInterce ...
- Spring AOP源码解析-拦截器链的执行过程
一.简介 在前面的两篇文章中,分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在得到了 bean 的代理对象,且通知也以合适的方式插在了目标方 ...
最新文章
- PrestaShop 网站漏洞修复如何修复
- 一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](三)
- 对话功率谱与自相关函数
- 如何刪除GitHub中的repository
- ROS初学笔记 - C++11与PCL库冲突问题
- 自然语言处理之AI深度学习顶级实战
- Android studio导入项目提示The same input jar [*.jar] is specified twice
- 【三】版本之间穿梭切换
- 从视图到控制器的传值方法(表单)
- Flutter实战一Flutter聊天应用(十三)
- Infortrend大数据时代广电行业应用
- debian网络配置文件的写法
- nod32/ESET下載及更新
- 服务器虚拟机怎么安装win7系统教程,虚拟机怎么安装系统?VMware虚拟机安装Win7和win10图文详细教程...
- VMWare SCSI硬盘识别
- spring cloud alibaba全家桶之nacos
- 学习UI设计,哪些软件是必学的
- 京东数科java一面【过】
- 用python输出pi的近似值_Python-Pi近似
- 网桥调用iptables规则的善后处理
热门文章
- Netty ObjectPool对象池技术原理分析
- 倍数应用题后面需要带单位吗_数学应用题解答思路解析(附例题)
- keep 虚拟路线修改器_keep儿童版下载-keep儿童模式6.124.0手机版下载
- c语言不同指令意识,C语言必须理清的概念1
- python时间模块哪个好arrow模块_python库: arrow (时间)
- java代码调用python_Java调用Python
- C语言引用文件空格和换行,关于文件操作,碰到空格就换行
- go 自定义error怎么判断是否相等_Go Web 小技巧(二)GORM 使用自定义类型
- Linux磁盘格式化和挂载
- nginx 上传文件漏洞_nginx爆惊天漏洞 上传图片就能入侵服务器