我们在开发过程中一般都有拦截器的概念,从最原始的Servlet里面有Filter,在Spring中,我们可以使用Interceptor来实现拦截;
基础概念
拦截器的应用场景
- 日志记录:记录请求信息的日志,以便于进行信息监控,信息统计,计算PV(Page View)等。
- 权限检查: 如登录检测
- 性能监控: 统计接收到请求到执行完的时间差,从而得出请求的处理时间;当然也可以在方向代理记录(如有)
- 通用行为:读取cookie,token等
拦截器与过滤器的区别
- 拦截器是基于Java的反射机制的,而过滤器是基于函数回调。
- 拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
- 拦截器只能对ACTION请求起作用,而过滤器则可以对几乎所有的请求起作用。
- 拦截器可以访问ACTION上下文、值栈里的对象,而过滤器不能访问。
- 在ACTION的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
- 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑
应用场景
- 用户登录,鉴权
- 接口性能记录
- 防重复提交
在项目中快速应用
在springboot中拦截器使用还是比较简,大概主要就两步:
- 实战HanderInterceptor接口创建拦截器;2.实现webMvcConfigurer接口配置拦截器
下面举个例子:
1. 定义一个HandlerInterceptor拦截器
@Slf4j
@Component
public class MyInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("进入之前,preHandle() ");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
log.info("调用执行之后,postHandle() ");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
log.info("完成处理逻辑之后,afterCompletion()");
}
}
2.实现Intgerceptor接口配置拦截器
在SpringBoot中不同版本,略有差异
其实SpringBoot2.0以前都是继承WebMvcConfigurerAdapter类,不过springBoot2.0以上 WebMvcConfigurerAdapter 方法过时,有两种替代方案:
1、继承WebMvcConfigurationSupport
2、实现WebMvcConfigurer
但是继承WebMvcConfigurationSupport会让Spring-boot对mvc的自动配置失效。根据项目情况选择。现在大多数项目是前后端分离,并没有对静态资源有自动配置的需求所以继承WebMvcConfigurationSupport也未尝不可。
集成WebMvcConfigurationSupport的实现方式
@Configuration
public class MyWebConfig extends WebMvcConfigurationSupport {
@Autowired
MyInterceptor myInterceptor;
public void addInterceptors(InterceptorRegistry registry) {
/** 需要拦截的路径 **/
String[] paths = {"/index", "/index/*"};
/** 不需要拦截的路径 **/
String[] excludePathPatterns = {};
registry.addInterceptor(myInterceptor).addPathPatterns(paths)
.excludePathPatterns(excludePathPatterns);
//可以注册多个,形成拦截链
}
}
实现WebMvcConfigurer的方式
@Configuration
@Slf4j
public class WebConfig implements WebMvcConfigurer {
@Autowired
TimeInterceptor timeInterceptor;
public void addInterceptors(InterceptorRegistry registry) {
String[] paths = {"/**"};
String[] excludePaths={"/login","/info"};
registry.addInterceptor(timeInterceptor).addPathPatterns(paths)
.excludePathPatterns();
}
}
这里需要重点说明细,如果以上两种实现都存在的,在存在优先级关系;当WebMvcConfigurationSupport与WebMvcConfigurer实现类同时存在时,WebMvcConfigurationSupport最终生效,而WebMvcConfigurer不会生效,这部分可以查看Spring中WebMvc的自动配置类WebMvcAutoConfiguration;
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
}
源码导读
以上,我们可以通过查看Spring源码。查看spring-webmvc包org.springframework.web.servlet.DispatcherServlet;doDispatch()
前置处理方法的调用
后置处理方法的调用
完成处理逻辑的调用
通过上面的代码调用也可以查看其源码实现逻辑,通过分析可以得出,在Springboot拦截器中方法执行的顺序是preHander ->Controller-->postHandle -->afterCompletion;只有preHandle返回true,才会执行后面的方法(此处可以直接看下Spring的源码)。