过滤器Filter和拦截器Interceptor

一、过滤器Filter

我们搭建一个简单demo:

1、自定义一个Filter类

public class LoginAuthFilter implements Filter {

    Logger logger = LoggerFactory.getLogger(LoginAuthFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //在Filter生命周期只会调用一次,可以读取配置文件
        logger.info("【过滤器】初始化");

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        logger.info("【过滤器】开始执行");
        filterChain.doFilter(servletRequest, servletResponse);
        logger.info("【过滤器】执行结束");
    }
}

2、注册过滤器


@Configuration
public class LoginAuthConfig {
    /**
     * 注册过滤器
     * @return
     */
    @Bean
    public FilterRegistrationBean getLoginAuthFilter(){
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        LoginAuthFilter filter = new LoginAuthFilter();
        registrationBean.setFilter(filter);
        //urlPatterns配置哪些路径的请求进入过滤器,/*表示所有
        registrationBean.addUrlPatterns("/*");
        return registrationBean;
    }
}

3、项目演示

@RestController
public class SysUserController {
    Logger logger = LoggerFactory.getLogger(SysUserController.class);
    @GetMapping(value = "/sysUser/getSysUserById")
    public String getSysUserById(String userId) {
        logger.info("Controller:进入方法getSysUserById()");
        return "嘻嘻嘻";
    }
 }

启动项目,SpringBoot初始化的时候,我们可以看到LoginAuthFilter类中的init()方法执行了一次

图片

接着我们使用postman请求接口,在控制台看到:

图片

在接口请求进入controller层前后,可以在过滤器Filter中处理一些前置后置逻辑。

二、拦截器Interceptor

1、自定义一个Interceptor类

@Component
public class MyInterceptor implements HandlerInterceptor {

    Logger logger = LoggerFactory.getLogger(MyInterceptor.class);

   @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("【拦截器】控制器方法调用前");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.info("【拦截器】控制器方法调用后,视图渲染前");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.info("【拦截器】整个请求完成后调用");
    }
}

2、注册拦截器


@Configuration
public class InterceptorConfig implements WebMvcConfigurer{
    @Autowired
    private MyInterceptor myInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor);
    }
}

3、项目演示

@RestController
public class SysUserController {
    Logger logger = LoggerFactory.getLogger(SysUserController.class);
    @GetMapping(value = "/sysUser/getSysUserById")
    public String getSysUserById(String userId) {
        logger.info("Controller:进入方法getSysUserById()");
        return "嘻嘻嘻";
    }
 }

启动项目,使用postman请求接口,控制台输出如下:

图片

在接口请求进入controler层的前后,拦截器Interceptor中,都有对应的方法,可以处理二开逻辑。

三、过滤器Filter和拦截器Interceptor的区别

  • 1、触发时机不同

  • 2、过滤器Filter中无法注入Bean,但是拦截器Interceptor中可以

当我们的项目中,既有过滤器Filter,又有拦截器Interceptor的时候,又出现什么的现象呢?

图片

图片

通过断点和日志输出,引出过滤器Filter和拦截器Interceptor一个区别:

1、触发时机不同

图片

  • 过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。

  • 拦截器 Interceptor 是在请求进入DispathServlet后,在进入Controller之前进行预处理的,视图渲染之后请求结束。我们在自定义类Interceptor的方法中打上断点,就可以看到都是在什么时机进入。

2、过滤器Filter中无法注入Bean,但是拦截器Interceptor中可以

我们写一个Service类,分别在过滤器Filter和拦截器Interceptor中注入,看下结果:

@Service
public class TestServiceImp {
    public void test(){
        System.out.println("测试方法");
    }
}

图片

图片

可以看到拦截器Interceptor中,是可以成功注入的,过滤器Filter中,testServiceImpl的值为null,无法注入。

这是因为我们在注册过滤器Filter的时候,使用的是new LoginAuthFilter的方式,过滤器是Servlet规范的一部分,而不是Spring框架的组件,需要通过new 关键字创建实例。Servlet容器并不了解Spring容器的上下文,因此它无法自动注入Spring的Bean到过滤器中。

而实例化拦截器Interceptor的时候,使用的@Autowired注解的方式。拦截器是Spring MVC框架的一部分,由Spring容器管理,因此可以通过@Autowired注解直接注入。

那如果我在LoginAuthFilter上,同样加上注解@Component,在配置类中使用@Autowired注入过滤器类,那LoginAuthFilter中的bean 可以成功注入吗?

答案是肯定的,可以成功注入bean。

这是为什么呢?不是说过滤器Filter不能注入bean吗?

    在一些特定情况下,你确实可以使用@Autowired注解来将过滤器(Filter)注入到Spring中,类似于拦截器(HandlerInterceptor)。   

     这是因为在Spring Boot等现代Web应用中,Spring容器和Servlet容器通常是集成的,而且Spring Boot提供了一些方便的工具来简化这个集成过程。

    尽管在某些情况下使用@Autowired注解是可能的,但需要注意的是,这种方式可能导致在一些纯Servlet容器环境下无法正常工作,因为过滤器的生命周期是由Servlet容器管理的。

这是我在网上查询到的答案。同时我还发现一个有趣的现象。

如果我们在LoginAuthFilter上,加上注解@Component,那么按理说testServiceImp 的bean应该可以成功注入,并且在后续逻辑中,可以正常使用才对。

但是如果你的注册过滤器的类LoginAuthConfig中,还是通过new LoginAuthFilter方法而不是@Autowired注入LoginAuthFilter,你会发现在拦截请求进入LoginAuthFilter中的时候,testServiceImp的bean还是为null 。


@Configuration
public class LoginAuthConfig {
    /**
     * 注册过滤器
     * @return
     */
    @Bean
    public FilterRegistrationBean getLoginAuthFilter(){
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        //exclusionsList 可以根据配置设置白名单
        LoginAuthFilter filter = new LoginAuthFilter();
        registrationBean.setFilter(filter);
        //urlPatterns配置哪些路径的请求进入过滤器,/*表示所有
        registrationBean.addUrlPatterns("/*");
        return registrationBean;
    }
}

图片

百思不得其解吧。不过好在springBoot启动的时候,我还发现一个情况:LoginAuthFilter中的init()方法,打印了两次日志,那也就意味着创建了两次实例。

初步猜测,是不是请求拦截的时候,使用的LoginAuthFilter是注册过滤器的时候new LoginAuthFilter的,而不是通过注解扫描创建出来的loginAuthFilter呢?

为了验证猜测,我们在init中打上断点,看下两个实例的情况。

图片

图片

springBoot启动完成后,请求接口:

图片

果然,此时请求进入的是:LoginAuthFilter@6189,对应的是new LoginAuthFilter创建的实例。

为什么拦截请求的时候,选择了使用new LoginAuthFilter的实例,而不是Spring注入的实例呢?这是我产生的第二个疑问。

通过debug查看源码,发现事情并不是我想象的这样必须是2选择1的,实际上注册的所有Filter实例,都会链式调用执行的。

图片

而我们在代码中所写的filterChain.doFilter(servletRequest, servletResponse),则是触发下一个Filter执行的逻辑。

new 方法创建的实例,只是在通过注解扫描创建的bean之前执行了,异常则中断了后续Filter的执行。

四、过滤器Filter和拦截器Interceptor的适用场景

适用场景:

  • 过滤器:广泛用于对请求和响应进行预处理和后处理的场景。例如,可以在过滤器中进行日志记录、字符编码转换、权限验证等操作。过滤器在请求进入Servlet容器或在响应返回客户端之前起作用。

  • 拦截器:主要用于在请求处理的不同阶段进行拦截和处理。在Spring等框架中,拦截器常用于对控制器的方法进行前后处理,如日志记录、权限检查、性能监控等。

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
filter过滤器拦截器是Web开发中常用的两种组件,它们在请求处理过程中起到了类似于"中间件"的作用,用于对请求进行处理和拦截。 Filter过滤器是Servlet规范中定义的一种组件,它可以对请求进行预处理和后处理。Filter可以拦截特定的URL请求,对请求进行处理,并将请求传递给下一个过滤器或Servlet。Filter可以用于对请求进行身份验证、日志记录、编码转换、资源过滤等等操作。一个应用可以配置多个Filter,它们按照配置的顺序依次执行。 拦截器是在Spring框架中使用的一种组件,它也可以对请求进行预处理和后处理。拦截器的使用更加灵活,可以对请求进行更加细粒度的控制。拦截器可以拦截Controller方法的调用,在方法执行前后做一些处理,例如身份验证、日志记录、性能监控等。一个应用可以配置多个拦截器,它们按照配置的顺序依次执行。 在使用上,filterinterceptor有一些区别: - Filter是基于Servlet规范的,而InterceptorSpring框架提供的; - Filter可以对所有的请求进行拦截,而Interceptor可以对Controller方法进行拦截; - Filter只能通过web.xml或注解进行配置,而Interceptor可以通过Java代码进行配置; - Interceptor可以访问Spring的上下文,而Filter不能。 总结来说,filterinterceptor都可以用于对请求进行处理和拦截,但是它们的具体实现和使用方式有一些差异。在使用时,可以根据具体需求选择适合的组件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值