一、过滤器(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加入到过滤器数组中。
然后将过滤器数组中的所有过滤器组成过滤器链,挨个执行过滤器的逻辑。