Java过滤器Filter和拦截器Interceptor

在日常的开发过程中,我们或多或少的会使用过滤器Filter或者拦截器Interceptor实现一些功能,但是好像并没有特别深入了解这两种机制。

  • 过滤器:广泛用于对请求和响应进行预处理和后处理的场景。例如,可以在过滤器中进行日志记录、字符编码转换、权限验证等操作。过滤器在请求进入Servlet容器或在响应返回客户端之前起作用。
  • 拦截器:主要用于在请求处理的不同阶段进行拦截和处理。在Spring等框架中,拦截器常用于对控制器的方法进行前后处理,如日志记录、权限检查、性能监控等。

过滤器Filter

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()方法执行了一次

Java过滤器Filter和拦截器Interceptor_第1张图片

接着我们使用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);
    }
}

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

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

区别

  • 触发时机不同
  • 过滤器Filter中无法注入Bean,但是拦截器Interceptor中可以

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

Java过滤器Filter和拦截器Interceptor_第2张图片

Java过滤器Filter和拦截器Interceptor_第3张图片

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

1、触发时机不同

Java过滤器Filter和拦截器Interceptor_第4张图片

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

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

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

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

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

Java过滤器Filter和拦截器Interceptor_第5张图片

Java过滤器Filter和拦截器Interceptor_第6张图片

可以看到拦截器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。

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

你可能感兴趣的:(【Java日常工作篇】,java,开发语言,servlet,spring,boot,intellij-idea)