拦截器Interceptor的使用

789 阅读3分钟

我们在开发过程中一般都有拦截器的概念,从最原始的Servlet里面有Filter,在Spring中,我们可以使用Interceptor来实现拦截;

基础概念

拦截器的应用场景

  1. 日志记录:记录请求信息的日志,以便于进行信息监控,信息统计,计算PV(Page View)等。
  2. 权限检查: 如登录检测
  1. 性能监控: 统计接收到请求到执行完的时间差,从而得出请求的处理时间;当然也可以在方向代理记录(如有)
  2. 通用行为:读取cookie,token等

拦截器与过滤器的区别

  1. 拦截器是基于Java的反射机制的,而过滤器是基于函数回调。
  2. 拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
  1. 拦截器只能对ACTION请求起作用,而过滤器则可以对几乎所有的请求起作用。
  2. 拦截器可以访问ACTION上下文、值栈里的对象,而过滤器不能访问。
  1. 在ACTION的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
  2. 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑

应用场景

  1. 用户登录,鉴权
  2. 接口性能记录
  1. 防重复提交

在项目中快速应用

在springboot中拦截器使用还是比较简,大概主要就两步:

  1. 实战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的源码)。