当前位置: 首页 > news >正文

过滤器和拦截器的区别

目录

1 前言

2 区别

2.1  实现原理不同

2.2 使用范围不同

2.3 执行顺序不同

4 注入Bean的情况不同

1 前言

        可能有些小伙伴们在接手公司的项目时,经常看到公司的项目中既有过滤器又有拦截器,那么它们既然都拦截的作用,那么各自扮演着什么样的角色呢?要想搞懂它们所扮演的角色,就需要搞懂它们各自有什么作用了。

2 区别

2.1  实现原理不同

1. 拦截器是基于java的反射机制,而过滤器是基于函数回调的。

2. 拦截器只能对action请求请作用,而过滤器对所有的请求都起作用

3. 拦截器可以访问action的上下文,而过滤器不能

4 在action的生命周期中,拦截器可以多次被调用,而过滤器只能调用一次

以下附有拦截器和过滤器的详细介绍:

java过滤器(Filter)_IT盛夏的果实的博客-CSDN博客

一篇搞懂拦截器(HandlerInterceptor)的用法_IT盛夏的果实的博客-CSDN博客

2.2 使用范围不同

 可见Filter过滤器是javax.servlet包下的,是在Servlet规范中定义的,也就是说过滤器Filter的使用依赖于Tomcat等容器,导致它只能在web程序中使用。

 拦截器是一个Sping组件,由Spring管理,不依赖于Tomcat容器,是可以单独使用的。也可以应用于Application、Swing容器中。

2.3 执行顺序不同

在有的项目中,既有过滤器又有拦截器,那么它们两者之间的执行顺序是谁先谁后呢?先过滤器->再拦截器

 在上面说过,Filter是依赖于Tomcat容器的,所以请求是在进入Tomcat之后、进入Servet之前对请求进行一个预处理,然后进入Servlet,再经过拦截器进行处理、最后进入我们的Controller。

为了证实上述所说:我们可以在一个项目中同时配置过滤器和拦截器(其余配置不在展示,可以参考上述两篇文章),

过滤器:

@WebFilter("/*")
public class MyFilterOne implements Filter {

    /**
     * web应用启动时,web服务器将创建Filter的实例对象,并调用init方法,读取web.xml的配置,完成对象的初始化功能,
     * 从而为后续的用户请求做好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次,开发人员通过init的参数,
     * 可或得代表当前filter配置信息的FilterConfig对象)
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    /**
     * 这个方法完成实际的过滤操作,当客户请求访问与过滤器相关联的URL的时候,Servlet过滤器将先执行doFilter方法,FilterChain参数用于访问后续过滤器
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("我是过滤器,我进来了");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    /**
     * filter创建后会保存在内存中,当web应用移除或者服务器停止时才销毁,该方法在Filter的生命周期中仅执行一次,在这个方法中,可以释放过滤器使用的资源
     */
    @Override
    public void destroy() {

    }
}

拦截器:


@Component
public class HeaderInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("进入拦截器=======执行前========");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("进入拦截器=======执行中========");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("进入拦截器=======执行后========");
    }
}

Controller层:

@RestController
public class LoginController {


    @GetMapping("/test/filterAndInterceptor")
    public String testFilter(){
     System.out.println("我是controller");
        return "请看控制台谁先输出";
    }
}

访问: 

控制台输出:

 可见:上述结论是正确的,请求先经过过滤器再经过拦截器。

4 注入Bean的情况不同

在有的业务场景中,会在过滤器或者拦器引入sevice,看看情况分别是怎么样

    @GetMapping("/test/filterAndInterceptor")
    public String testFilter(){
        System.out.println("我是controller");
        return "请看控制台谁先输出";
    }
@Service
public class LoginServiceImpl implements LoginService{
    @Override
    public void login() {
        System.out.println("我是service中登录方法");
    }
}

在过滤器中引入service:

package com.liubujun.springbootinterceptor.filter;




import com.liubujun.springbootinterceptor.service.LoginService;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * @Author: liubujun
 * @Date: 2022/10/16 19:26
 */

@WebFilter("/*")
public class MyFilterOne implements Filter {

    @Resource
    private LoginService loginService;

    /**
     * web应用启动时,web服务器将创建Filter的实例对象,并调用init方法,读取web.xml的配置,完成对象的初始化功能,
     * 从而为后续的用户请求做好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次,开发人员通过init的参数,
     * 可或得代表当前filter配置信息的FilterConfig对象)
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    /**
     * 这个方法完成实际的过滤操作,当客户请求访问与过滤器相关联的URL的时候,Servlet过滤器将先执行doFilter方法,FilterChain参数用于访问后续过滤器
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("我是过滤器,我进来了");
        loginService.login();
        filterChain.doFilter(servletRequest, servletResponse);
    }

    /**
     * filter创建后会保存在内存中,当web应用移除或者服务器停止时才销毁,该方法在Filter的生命周期中仅执行一次,在这个方法中,可以释放过滤器使用的资源
     */
    @Override
    public void destroy() {

    }
}

访问之后控制台输出:一切正常

 在拦截器中引入service :

@Component
public class HeaderInterceptor implements HandlerInterceptor {

    @Resource
    private LoginService loginService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("进入拦截器=======执行前========");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        loginService.login();
        System.out.println("进入拦截器=======执行中========");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("进入拦截器=======执行后========");
    }
}

发起请求:发现竟然报错了。

打断点之后发现:拦截器中注入的service为null。

 那么为什么会出现这种情况呢?这是因为加载顺序导致的问题,拦截器的加载时间点在springcontext之前,而bean是由Spring管理。所以为null。

那么如何修改呢?

@Configuration
public class WebAppConfig implements WebMvcConfigurer {

    @Resource
    private HeaderInterceptor headerInterceptor;

    /**
     * 添加拦截规则
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        List<String> patterns = new ArrayList<>();

        patterns.add("/login/login");

        registry.addInterceptor(headerInterceptor)
                .addPathPatterns("/**") //所有的请求都要拦截。
                .excludePathPatterns(patterns); //将不需要拦截的接口请求排除在外
    }
}

之前是这样的: 

@Configuration
public class WebAppConfig implements WebMvcConfigurer {


    /**
     * 添加拦截规则
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new HeaderInterceptor());

    }
}

再次测试发现就不会报错了。

参考文章:拦截器(Interceptor)和过滤器(Filter)的执行顺序和区别_熊與猫v的博客-CSDN博客_filter和interceptor执行顺序

相关文章:

  • i.MX 6ULL 驱动开发 十九:RGBLCD
  • 前端谷歌浏览器基本介绍及前后端分离原理分析
  • Day12-尚品汇-trade静态组件
  • 十大排序算法(java实现万字详解)
  • Qt文档阅读笔记-Hello Speak Example
  • 【Golang开发面经】知乎(两轮技术面)
  • 1024程序员节:从关注自身健康开始
  • 负载均衡式在线OJ
  • SQL注入天书笔记(1)布尔盲注
  • 【2022集创赛】安谋科技杯一等奖作品:Cortex-M0智能娱乐收音机
  • python3-python中的多任务处理利器-协程的使用(一),asyncio模块的使用
  • vue06安装vue-cli+使用vue-cli搭建项目+什么是*.vue文件+开发示例+必问面试知识点
  • chrome盗取用户身份
  • 队列(Queue)的详解
  • 快速发布windows上的web项目【免费内网穿透】
  • [NodeJS] 关于Buffer
  • Angular 响应式表单 基础例子
  • C++类中的特殊成员函数
  • classpath对获取配置文件的影响
  • Django 博客开发教程 8 - 博客文章详情页
  • ES6语法详解(一)
  • Git学习与使用心得(1)—— 初始化
  • js数组之filter
  • k8s 面向应用开发者的基础命令
  • Making An Indicator With Pure CSS
  • PAT A1092
  • React-Native - 收藏集 - 掘金
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 嵌入式文件系统
  • 如何胜任知名企业的商业数据分析师?
  • 网页视频流m3u8/ts视频下载
  • 应用生命周期终极 DevOps 工具包
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 做一名精致的JavaScripter 01:JavaScript简介
  • UI设计初学者应该如何入门?
  • 教程:使用iPhone相机和openCV来完成3D重建(第一部分) ...
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • #Z0458. 树的中心2
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (03)光刻——半导体电路的绘制
  • (1)SpringCloud 整合Python
  • (4) PIVOT 和 UPIVOT 的使用
  • (Python第六天)文件处理
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (一)搭建springboot+vue前后端分离项目--前端vue搭建
  • (一一四)第九章编程练习
  • **python多态
  • .NET 设计模式初探
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .NET 中 GetProcess 相关方法的性能
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件