文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

过滤器Filter和拦截器Interceptor的联系和区别

2024-12-02 09:59

关注

本文将对拦截器Interceptor进行简单讲解,并通过几个例子对它们的差异进行简要分析。

拦截器Interceptor简介

一个应用中可以定义多个拦截器,spring在项目启动时,会将这些拦截器注册进来,并按照默认规则进行排序。如果是自定义的拦截器,可手动设置拦截器调用的先后顺序。

各拦截器是链式调用,一个请求可以触发多个拦截器,每个拦截器的调用会按照它加载到spring中的顺序依次执行。

拦截器中有3个方法,功能如下:

自定义拦截器Interceptor 

  1. public class MyInterceptor implements HandlerInterceptor { 
  2.     @Override 
  3.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
  4.         System.out.println("调用preHandle"); 
  5.         return true
  6.     } 
  7.  
  8.     @Override 
  9.     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 
  10.         System.out.println("调用postHandle"); 
  11.     } 
  12.  
  13.     @Override 
  14.     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 
  15.         System.out.println("调用afterCompletion"); 
  16.     } 

注册自定义拦截器Interceptor

编写配置类并实现WebMvcConfigurer接口。 

  1. @Configuration 
  2. public class MyWebConfig implements WebMvcConfigurer { 
  3.     @Override 
  4.     public void addInterceptors(InterceptorRegistry registry) { 
  5.         registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**"); 
  6.     } 

过滤器Filter和拦截器Interceptor区别

过滤器和拦截器都可以实现例如编码设置、日志记录、权限控制等功能,但是二者还是有很多区别的。

(1)实现原理不同

Filter是基于函数回调实现的:

每个自定义过滤器都会实现一个doFilter()方法,这个方法有一个关键参数FilterChain。它是一个回调接口,ApplicationFilterChain是它的具体实现类,该类内部也有一个doFilter()方法,这个方法就是回调方法(ps:可以理解为方法递归调用,查看源码比较容易理解)。

假设有2个滤器,调用流程图如下(ps:画的比较抽象): 

两个过滤器执行流程 

Interceptor是基于反射实现的:

为什么说拦截器是基于反射实现的呢?个人理解在拦截器内部的三个方法中,都有一个共同的参数handler,这个参数里包含的信息比较丰富。包含该请求所对应的方法、方法所在的Controller、方法参数等信息,而这些信息都是spring通过反射加载进来的。正是由于这些丰富的参数,使得拦截的功能相比过滤器功能更强大。 

 handler参数信息 

(2)使用范围不同

过滤器Filter实现了javax.servlet.Filter接口,也就是说过滤器的使用要依赖于Tomcat等容器,所以它只能在web程序中使用。

拦截器Interceptor实现了

org.springframework.web.servlet接口,它是由Spring容器进行管理,并不依赖Tomcat等容器,既可以应用在web程序中,也可以应用在非web程序中。

(3)触发时机不同

过滤器Filter是在请求进入Tomcat等容器后,servlet处理之前进行调用的。

拦截器Interceptor是在请求进入servlet后,执行Controller之前进行调用的。

(4)拦截范围不同

过滤器Filter几乎可以拦截所有进入容器的请求。

拦截器Interceptor只会对Controller请求或访问static目录下的静态资源请求起作用。

(5)初始化时机不同

过滤器Filter是随着Tomcat等web容器启动时而进行初始化。

拦截器Interceptor时随着spring启动而进行初始化。

过滤器和拦截器如何注入依赖服务

在实际开发中,当使用到过滤器或拦截器时,难免会引入一些依赖的service服务。下面就通过例子进行简要说明:

Filter依赖service:直接采用注解@Autowired即可。 

  1. @WebFilter(urlPatterns = {"/user/*"}) 
  2. @Log4j2 
  3. public class MyFilter implements Filter { 
  4.     @Autowired 
  5.     private UserService userService; 
  6.      
  7.     @Override 
  8.     public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { 
  9.         HttpServletRequest httpServletRequest = (HttpServletRequest) request; 
  10.         log.info("Filter获取到请求地址:" + httpServletRequest.getServletPath()); 
  11.         filterChain.doFilter(request, response); 
  12.  
  13.         HttpServletResponse httpServletResponse = (HttpServletResponse) response; 
  14.         log.info("Filter获取到响应类型:" + httpServletResponse.getContentType()); 
  15.     } 
  16.  
  17.     @Override 
  18.     public void init(FilterConfig filterConfig) throws ServletException { 
  19.         System.out.println("Filter随着项目的启动而启动,只初始化一次"); 
  20.     } 
  21.  
  22.     @Override 
  23.     public void destroy() { 
  24.         System.out.println("Filter随着web项目的停止而销毁,完成资源回收"); 
  25.     } 

Interceptor依赖service:直接采用注解@Autowired,但是在将拦截器注入到spring容器中时,不能自己通过new来进行创建。需要将拦截器当做一个普通的bean注入到spring容器中,这样就可以将service注入到拦截器中。 

  1. public class MyInterceptor implements HandlerInterceptor { 
  2.     @Autowired 
  3.     private UserService userService; 
  4.      
  5.     @Override 
  6.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
  7.         System.out.println("调用preHandle"); 
  8.         return true
  9.     } 
  10.  
  11.     @Override 
  12.     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 
  13.         System.out.println("调用postHandle"); 
  14.     } 
  15.  
  16.     @Override 
  17.     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 
  18.         System.out.println("调用afterCompletion"); 
  19.     } 

 

  1. @Configuration 
  2. public class MyWebConfig implements WebMvcConfigurer { 
  3.  
  4.     @Bean 
  5.     public MyInterceptor getMyInterceptor(){ 
  6.         return new MyInterceptor(); 
  7.     } 
  8.  
  9.     @Override 
  10.     public void addInterceptors(InterceptorRegistry registry) { 
  11.         // getMyInterceptor()这种注册方式可以在拦截器里注入bean 
  12.         registry.addInterceptor(getMyInterceptor()).addPathPatterns("/**"); 
  13.         // 这种注册方式由于是自己new出来的,所以在拦截器里注册的bean都为null 
  14.         registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**"); 
  15.     } 

过滤器和拦截器如何指定加载顺序

(1)Filter:需要通过配置类指定加载顺序,值越小,越先执行。采用@WebFilter无法指定顺序。 

  1. @Bean 
  2. public FilterRegistrationBean myFilter(){ 
  3.     MyFilter myFilter = new MyFilter(); 
  4.     FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter); 
  5.     filterRegistrationBean.setUrlPatterns(Arrays.asList("/user/*")); 
  6.     filterRegistrationBean.setOrder(2); 
  7.     return filterRegistrationBean; 

(2)Interceptor:需要通过配置类指定加载顺序,值越小,越先执行。 

  1. @Configuration 
  2. public class MyWebConfig implements WebMvcConfigurer { 
  3.     @Override 
  4.     public void addInterceptors(InterceptorRegistry registry) { 
  5.         // getMyInterceptor()这种注册方式可以在拦截器里注入bean 
  6.         registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").order(1); 
  7.         // 这种注册方式由于是自己new出来的,所以在拦截器里注册的bean都为null 
  8.         registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**").order(2); 
  9.     } 

过滤器Filter和拦截器Interceptor使用场景

二者相比拦截器功能更强大些,Filter能做的事情,它都能做,而且可以在请求前,请求后执行,比较灵活。Filter主要用来设置字符编码、过滤敏感词汇和URL级别的简单权限控制。如果需要记录比较详细的信息或比较复杂的权限管理,还是建议用拦截器实现。

拓展

Servlet和Controller的区别是什么?

使用Servlet可以收集来自网页表单的用户输入,还可以动态创建网页。DispatcherServlet是SpringMVC中唯一的Servlet,Servlet容器(Tomcat)把所有的请求都转发到DispatcherServlet,然后通过HandlerMapping把请求路由到具体的Controller中。因此,Controller只是一个普通的Java Bean。

 

来源:今日头条内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯