Java Web之路一:过滤器,Filter

一、过滤器(Filter)简介

过滤器是对web资源进行拦截,做一些处理后再交给下一个过滤器或Servlet处理,主要可以拦截request和response

过滤器是以一种组件的形式与web程序绑定,采用链式进行工作。

过滤器的好处:

可以拦截请求和响应,以便查看或者获取客户端与服务器之间的交互数据,实现过滤的功能。另外过滤器可以动态的添加或删除而不需要修改web程序的逻辑。

过滤器的初始化和销毁都是通过Web容器来实现的,Web容器初始化Filter对象之后会执行init方法,销毁Filter对象之前会执行destory方法。

二、过滤器的使用

2.1、Filter基本使用

Servlet中Filter接口的定义如下:

public interface Filter {

    /**过滤器的初始化时被调用*/
    public void init(FilterConfig filterConfig) throws ServletException;

  
    /**执行过滤器处理逻辑*/
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;

   /**销毁过滤器时被调用*/
    public void destroy();

}

其中init方法是在Filter初始化时会被调用、destroy方法是Filter被销毁时调用,而doFilter方法是过滤器的工作时执行的方法,doFilter至少需要保护两块逻辑,一个是当前过滤器需要处理的过滤逻辑,一个是跳转到下一个过滤器中。

如下自定义的过滤器:

public class LogFilter implements Filter {

    /**初始化过滤器时调用*/
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化过滤器");
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("执行过滤器逻辑");
        //跳转到过滤器链路到下一个链路
        chain.doFilter(request, response);
    }

    public void destroy() {
        System.out.println("销毁过滤器");
    }
}

本文采用SpringBoot方式,Filter的配置类如下:

    @Bean
    public FilterRegistrationBean initLogFilter(){
        FilterRegistrationBean bean = new FilterRegistrationBean();
        LogFilter filter = new LogFilter();
        bean.setFilter(filter);
        //需要过滤的URL路径
        List<String> urls = new ArrayList<String>();
        urls.add("/manage/*");//只过滤 /manage/*的路径
        bean.setUrlPatterns(urls);
        return bean;
    }

    @Bean
    public FilterRegistrationBean initTimeFilter(){
        FilterRegistrationBean bean = new FilterRegistrationBean();
        TimeFilter filter = new TimeFilter();
        bean.setFilter(filter);
        //需要过滤的URL路径
        List<String> urls = new ArrayList<String>();
        urls.add("/*");//过滤所有路径
        bean.setUrlPatterns(urls);
        return bean;
    } 

自定义过滤器需要实现Filter接口,重写Filter接口的三个方法,然后配置Filter即可,项目启动时会执行init方法,项目关闭时会执行destory方法,客户端每次发起请求都会执行一次doFilter方法,doFilter必须执行chain.doFilter方法将请求转发到下一个过滤器,

否则最终的请求就无法达到业务层逻辑,多个Filter的执行顺序和配置的执行顺序一样,先配置的就先执行,也可以手动设置不同的Filter的执行顺序,理论上各个Filter直接是相互独立的。

2.2、Filter的进阶使用

实战情况下不同的Filter需要过滤的路径可能不一样,可以通过设置不同的Filter过滤不同的路径,如上例中LogFilter只拦截 /manage/* 路径的请求,而TimeFilter会过滤所有的请求;

另外除了过滤的路径,不同的Filter也可以手动设置不同的执行顺序,可以通过@Order注解来设置,而且Spring还提供了@WebFilter注解可以直接定义Filter,而不需要单独再用@Bean注解来定义,用法如下:

@WebFilter(urlPatterns = "/*")
@Order(1)
public class LogFilter implements Filter {
   
    //...............

}
@WebFilter(urlPatterns = "/manage/*")
@Order(2)
public class TimeFilter implements Filter {

   //......
 
}

定义了两个Filter,其中LogFilter执行顺序为第一个,并且过滤所有请求;TimeFilter执行顺序为第二个,过滤 /manage/* 路径的请求

而@WebFilter注解是Servlet的注解,所以需要在启动类中加上Servlet注解的扫描注解 @ServletComponentScan,如下示:

@SpringBootApplication
@ServletComponentScan
public class Bootstrap
{
    public static void main( String[] args )
    {
        SpringApplication.run(Bootstrap.class);
    }
}

三、Filter的实现原理

Filter和Servlet一样都是通过Web容器实现的,Web容器分别存了Servlet和Filter的两个Map,key是对应配置的路径url-parttern,value分别就是Servlet和Filter的实例

在web容器启动时就会初始化所有的Filter,并且将所有的Filter存入Map中,每次当有客户端请求来时,web容器都会先获取请求的url,然后遍历所有的Filter,如果Filter满足URL的条件,就将Filter加入到过滤器数组中。

然后将过滤器数组中的所有过滤器组成过滤器链,挨个执行过滤器的逻辑。