Spring 拦截器实现+后台原理(HandlerInterceptor)

时间:2020-12-04 23:36:18

过滤器跟拦截器的区别

spring mvc的拦截器是只拦截controller而不拦截jsp,html 页面文件的。这就用到过滤器filter了,filter是在servlet前执行的,你也可以理解成过滤器中包含拦截器,一个请求过来 ,先进行过滤器处理,看程序是否受理该请求 。 过滤器放过后 , 程序中的拦截器进行处理 。

1、拦截器不依赖servlet容器,过滤器依赖;

2、拦截器是基于java反射机制来实现的,过滤器基于回调

过滤器:关注web请求;

拦截器:关注方法调用;

Spring拦截器分类

spring中拦截器主要分两种,一个是HandlerInterceptor,一个是MethodInterceptor。

HandlerInterceptor

HandlerInterceptor是springMVC项目中的拦截器,它拦截的目标是请求的地址,比MethodInterceptor先执行。

HandlerInterceptor拦截的是请求地址,所以针对请求地址做一些验证、预处理等操作比较合适。当你需要统计请求的响应时间时MethodInterceptor将不太容易做到,因为它可能跨越很多方法或者只涉及到已经定义好的方法中一部分代码。

实现一个HandlerInterceptor拦截器可以直接实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter类。

看下UML:

Spring 拦截器实现+后台原理(HandlerInterceptor)

HandlerInterceptorAdapter.class
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
public HandlerInterceptorAdapter() {
}
   //在业务处理器处理请求之前被调用
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
  //在业务处理器处理请求完成之后,生成视图之前执行  
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
   // 在DispatcherServlet完全处理完请求之后被调用,可用于清理资源  
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
} public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
}
}

执行顺序如图:

Spring 拦截器实现+后台原理(HandlerInterceptor)

具体体现在 DispatcherServlet.class  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) {
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 ((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);
} }
}

现在需要一个简单的demo,深入了解几个方法:

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; public class SecurityInterceptor extends HandlerInterceptorAdapter { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("SecurityInterceptor >>>>>>>>1"); return true;
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class WebSecurityConfig extends WebMvcConfigurationSupport { @Bean
public SecurityInterceptor getSecurityInterceptor() {
return new SecurityInterceptor();
} @Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration addInterceptor = registry.addInterceptor(getSecurityInterceptor()); // 排除配置
addInterceptor.excludePathPatterns("/403");
addInterceptor.excludePathPatterns("/toLogin");
addInterceptor.excludePathPatterns("/login**"); // 拦截配置
addInterceptor.addPathPatterns("/**");
}
}

启动工程(springboot工程):

请求:http://localhost:8080/toLogin ,因为配置了排除设置,后台无打印。

Spring 拦截器实现+后台原理(HandlerInterceptor)

请求:http://localhost:8080/userInfo/userAdd,后台有打印。

Spring 拦截器实现+后台原理(HandlerInterceptor)

Spring 拦截器实现+后台原理(HandlerInterceptor)

发散:如果是多个拦截器,他们preHandle、postHandle、afterCompletion方法执行顺序是什么?

看下demo:

import org.springframework.lang.Nullable;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; public class SecurityInterceptor extends HandlerInterceptorAdapter { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("SecurityInterceptor.preHandle >>>>>>>>1"); return true;
} public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("SecurityInterceptor.postHandle >>>>>>>>1");
} public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("SecurityInterceptor.afterCompletion >>>>>>>>1");
}
}
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; public class HelloInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("HelloInterceptor.preHandle >>>>>>>>3");
return true;
} public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("HelloInterceptor.postHandle >>>>>>>>3");
} public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("HelloInterceptor.afterCompletion >>>>>>>>3");
}
}
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; public class RoleAuthorizationInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("RoleAuthorizationInterceptor.preHandle >>>>>>>>2");
return true;
} public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("RoleAuthorizationInterceptor.postHandle >>>>>>>>2");
} public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("RoleAuthorizationInterceptor.afterCompletion >>>>>>>>2");
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class WebSecurityConfig extends WebMvcConfigurationSupport { @Bean
public SecurityInterceptor getSecurityInterceptor() {
return new SecurityInterceptor();
} @Bean
public HelloInterceptor getHelloInterceptor() {
return new HelloInterceptor();
} @Bean
public RoleAuthorizationInterceptor getRoleAuthorizationInterceptor() {
return new RoleAuthorizationInterceptor();
} @Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration addInterceptor = registry.addInterceptor(getSecurityInterceptor()); // 排除配置
addInterceptor.excludePathPatterns("/403");
addInterceptor.excludePathPatterns("/toLogin");
addInterceptor.excludePathPatterns("/login**"); // 拦截配置
addInterceptor.addPathPatterns("/**"); InterceptorRegistration roleInter = registry.addInterceptor(getRoleAuthorizationInterceptor());
// 拦截配置
roleInter.addPathPatterns("/**"); InterceptorRegistration helloInter = registry.addInterceptor(getHelloInterceptor());
helloInter.addPathPatterns("/**"); }
}

执行结果:

Spring 拦截器实现+后台原理(HandlerInterceptor)

如果拦截器的preHandle()返回false,结果会怎样,改下demo:

WebSecurityConfig.java

 @Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration addInterceptor = registry.addInterceptor(getSecurityInterceptor()); // 排除配置
/*addInterceptor.excludePathPatterns("/403");
addInterceptor.excludePathPatterns("/toLogin");
addInterceptor.excludePathPatterns("/login**");*/ // 拦截配置
addInterceptor.addPathPatterns("/**"); InterceptorRegistration roleInter = registry.addInterceptor(getRoleAuthorizationInterceptor());
// 拦截配置
roleInter.addPathPatterns("/**"); InterceptorRegistration helloInter = registry.addInterceptor(getHelloInterceptor());
helloInter.addPathPatterns("/**"); }
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("RoleAuthorizationInterceptor.preHandle >>>>>>>>2");
return false;
}

其他不变,运行结果:

Spring 拦截器实现+后台原理(HandlerInterceptor)

通过源码分析,当prehandle返回false,则执行triggerAfterCompletion()执行拦截器的afterCompletion()方法。

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
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;
}

如果preHandle都返回true,postHandle()异常,又会是什么情况呢?

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("RoleAuthorizationInterceptor.postHandle >>>>>>>>2");
throw new NullPointerException();
}

结果:

Spring 拦截器实现+后台原理(HandlerInterceptor)

结论:

1、如果多个拦截器,执行顺序:preHandle() :123 ,postHandle():321,afterCompletion():321

2、preHandle() 返回false,不会往下执行

3、preHandle()返回true的拦截器,必然会执行他的afterCompletion();

4、如果preHandle()都返回true,有一个拦截器的postHandle()抛出异常,则后面拦截器的postHandle()不会执行。(注意:写代码时要注意)

参考:

https://www.cnblogs.com/niceyoo/p/8735637.html

Spring 拦截器实现+后台原理(HandlerInterceptor)的更多相关文章

  1. Spring 拦截器实现&plus;后台原理(MethodInterceptor)

    MethodInterceptor MethodInterceptor是AOP项目中的拦截器(注:不是动态代理拦截器),区别与HandlerInterceptor拦截目标时请求,它拦截的目标是方法. ...

  2. &lbrack;十四&rsqb;SpringBoot 之 Spring拦截器(HandlerInterceptor)

    过滤器属于Servlet范畴的API,与spring 没什么关系. Web开发中,我们除了使用 Filter 来过滤请web求外,还可以使用Spring提供的HandlerInterceptor(拦截 ...

  3. Spring 拦截器——HandlerInterceptor

    采用Spring拦截器的方式进行业务处理.HandlerInterceptor拦截器常见的用途有: 1.日志记录:记录请求信息的日志,以便进行信息监控.信息统计.计算PV(Page View)等. 2 ...

  4. Spring拦截器和过滤器

    什么是拦截器 拦截器(Interceptor): 用于在某个方法被访问之前进行拦截,然后在方法执行之前或之后加入某些操作,其实就是AOP的一种实现策略.它通过动态拦截Action调用的对象,允许开发者 ...

  5. spring 拦截器简介

    spring 拦截器简介 常见应用场景 1.日志记录:记录请求信息的日志,以便进行信息监控.信息统计.计算PV(Page View)等.2.权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直 ...

  6. struts2拦截器的实现原理

    拦截器(interceptor)是Struts2最强大的特性之一,也可以说是struts2的核心,拦截器可以让你在Action和result被执行之前或之后进行一些处理.同时,拦截器也可以让你将通用的 ...

  7. Spring拦截器中通过request获取到该请求对应Controller中的method对象

    背景:项目使用Spring 3.1.0.RELEASE,从dao到Controller层全部是基于注解配置.我的需求是想在自定义的Spring拦截器中通过request获取到该请求对应于Control ...

  8. spring拦截器中修改响应消息头

    问题描述 前后端分离的项目,前端使用Vue,后端使用Spring MVC. 显然,需要解决浏览器跨域访问数据限制的问题,在此使用CROS协议解决. 由于该项目我在中期加入的,主要负责集成shiro框架 ...

  9. struts2拦截器的实现原理及源码剖析

    拦截器(interceptor)是Struts2最强大的特性之一,也可以说是struts2的核心,拦截器可以让你在Action和result被执行之前或之后进行一些处理.同时,拦截器也可以让你将通用的 ...

随机推荐

  1. 为linux普通用户添加超级用户权限sudo

    问题:假设用户名为:ali如果用户名没有超级用户权限,当输入 sudo + 命令 时, 系统提示: ali is not in the sudoers file.  This incident wil ...

  2. iOS Xcode 调试技巧 全局断点这样加才有意思

    http://blog.sina.com.cn/s/blog_876a2c9901016ezh.html

  3. 感兴趣的Linux发行版

    1. Ubuntu,包括KUbuntu,XUbuntu,Kyrin等等 2. BluestarLinux - 基于Arch Linux,感觉很美 http://sourceforge.net/proj ...

  4. CSS彻底研究&lpar;2&rpar;

    Github pages 博文 一 . CSS盒模型 1.盒子的结构 margin-border-padding结构 + 内容content 组成盒模型 注意 width,height 取的是cont ...

  5. Ubuntu Server修改IP、DNS、hosts

    本文记录下Ubuntu Server 16.04修改IP.DNS.hosts的方法 -------- 1. Ubuntu Server 修改IP sudo vi /etc/network/interf ...

  6. 吴恩达机器学习笔记 —— 19 应用举例:照片OCR(光学字符识别)

    http://www.cnblogs.com/xing901022/p/9374258.html 本章讲述的是一个复杂的机器学习系统,通过它可以看到机器学习的系统是如何组装起来的:另外也说明了一个复杂 ...

  7. 【转】浅谈Java中的hashcode方法

    哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native int hashCode(); 根据这个 ...

  8. ASP&period;NET Core 中读取 Request&period;Body 的正确姿势

    ASP.NET Core 中的 Request.Body 虽然是一个 Stream ,但它是一个与众不同的 Stream —— 不允许 Request.Body.Position=0 ,这就意味着只能 ...

  9. 转 消息中间件:RocketMQ 介绍(特性、术语、原理、优缺点、消息顺序、消息重复)

    https://blog.csdn.net/jiangyu1013/article/details/81668671 消息中间件的作用 1. 应用解耦 2. 异步处理 比如用户注册场景,注册主流程完成 ...

  10. Spring 框架下 事务的配置(复杂)

    //db.properties配置  src下的文件 jdbc.jdbcUrl=jdbc:mysql:///day43jdbc.driverClass=com.mysql.jdbc.Driverjdb ...