Spring Boot学习(十四):Java三大器之一!Spring Boot的过滤器使用秘籍

过滤器(Filter)

过滤器,顾名思义就是用于过滤某些我们不需要的东西,留下符合我们要求的东西。


拦截器与过滤器的区别


1、过滤器执行由Servlet容器回调完成,拦截器则是基于Java的反射机制(动态代理)实现的。

2、Filter是依赖于Servlet容器,属于Servlet规范的一部分,也就是说过滤器Filter 的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。而拦截器是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器,是可以单独使用的。

3、过滤器的执行是在过滤器之前的,请求需要先通过了过滤器的过滤,然后进入Servlet,拦截器才会起作用。


补充一个拦截器的知识点:

当我们想在拦截器注入其他bean的时候,我们会发现会抛出nested exception is java.lang.NullPointerException异常。这是因为加载顺序导致的,拦截器加载的时间点在springcontext之前,而Bean又是由spring进行管理。

而解决方法也很简单:我们在注册拦截器之前,先将Interceptor 手动进行注入。

注意:此时addInterceptor方法注入的实例就是我们的注册方法testInterceptor()

修改一下我们上一篇文章的拦截器后,就可以在拦截器注入bean了:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public TestInterceptor testInterceptor(){
        return new TestInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(testInterceptor()).addPathPatterns("/**");
    }
}

自定义过滤器

自定义过滤很简单,只需要实现 javax.Servlet.Filter 接口,然后重写里面的方法就可以了

下面是Filter的源码

public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    default void destroy() {
    }
}

init() :该方法在容器启动初始化过滤器时被调用,它在 Filter 的整个生命周期只会被调用一次。

doFilter() :对请求进行过滤

FilterChain 接口
该接口用于定义一个 Filter 链的对象应该对外提供的方法,这个接口只定义了一个 doFilter 方法。

public void doFilter(ServletRequest request, ServletResponse response) throws java.io.IOException.ServletException

FilterChain 接口的 doFilter 方法用于通知 Web 容器把请求交给 Filter 链中的下一个 Filter 去处理,如果当前调用此方法的 Filter 对象是Filter 链中的最后一个 Filter,那么将把请求交给目标 Servlet 程序去处理。

destroy():当容器销毁过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次


过滤器的工作流程

1、当 Servlet 容器开始调用某个 Servlet 程序时,如果发现已经注册了一个 Filter 程序来对该 Servlet 进行拦截,那么容器不再直接调用 Servlet 的 service 方法,而是调用 Filter 的 doFilter 方法,再由 doFilter 方法决定是否去激活 service 方法。

2、但在 Filter.doFilter 方法中不能直接调用 Servlet 的 service 方法,而是调用 FilterChain.doFilter 方法来激活目标 Servlet 的 service 方法,FilterChain 对象时通过 Filter.doFilter 方法的参数传递进来的。

3、只要在 Filter.doFilter 方法中调用 FilterChain.doFilter 方法的语句前后增加某些程序代码,这样就可以在 Servlet 进行响应前后实现某些特殊功能。

4、如果在 Filter.doFilter 方法中没有调用 FilterChain.doFilter 方法,则目标 Servlet 的 service 方法不会被执行,这样通过 Filter 就可以阻止某些非法的访问请求。

示意图:

在这里插入图片描述


配置过滤器

配置过滤器有两种方法,一种是在配置类进行配置,另一种是通过@WebFilter注解进行配置

1、配置类配置

创建一个自定义配置类,用@Component将过滤器交给spring管理

@Component
public class TestFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤器开始执行:"+System.currentTimeMillis());
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("过滤器处理响应:"+System.currentTimeMillis());
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}


创建配置类,配置过滤器

@Configuration
public class MyFilterConfig {
    @Autowired
    TestFilter testFilter;

    @Bean
    public FilterRegistrationBean<TestFilter> thirdFilter() {
        FilterRegistrationBean<TestFilter> filterRegistrationBean = new FilterRegistrationBean<>();

        filterRegistrationBean.setFilter(testFilter);
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.setUrlPatterns(new ArrayList<>(Arrays.asList("/*")));

        return filterRegistrationBean;
    }
}

filterRegistrationBean 为过滤器的注册bean

setFilter表示设置过滤器

setUrlPatterns表示过滤的路径

setOrder表示Filter 的执行顺序,越小越先执行



2、注解配置

在自定义过滤器上加上@WebFilter注解,filterName表示过滤器名称,urlPatterns 表示过滤的路径

@WebFilter(filterName = "MyFilterWithAnnotation", urlPatterns = "/*")
public class TestFilter implements Filter {
....
}

在启动类上加上@ServletComponentScan注解,使spring扫描到@WebFilter

@SpringBootApplication
@ServletComponentScan
public class DemoApplication 

测试

我在上一篇拦截器的代码基础上加上过滤器,大家看一下输出的结果
在这里插入图片描述
可以看到,过滤器是在拦截器的preHandle方法之前执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值