1. 概念
filter 过滤器, 对从客户端向服务端发送的请求进行过滤,也可以对服务端返回的响应进行处理。Filter 不是Servlet,它不能产生一个response,它能否在一个request到达servlet之前预处理request,也可以在response离开servlet时处理response。
注意:
Filter 只能拦截请求和响应,不能产生响应,而servlet是用来处理请求并产生响应的
2.应用场景
- 权限认证
- 敏感词过滤
- 压缩响应等
3. Filter 拦截流程
- 当客户端发送请求后,在HttpServletRequest到达Servlet之前,Filter拦截客户端的HttpServletRequest
- 根据需要检查HttpServletRequest
- 在Filter调用doFilter对过滤放行。
- 到达Servlet后,处理请求,并产生HttpServletResponse响应给客户端
- 在HttpServletResponse到达客户端之前过滤拦截
- 根据需要对HttpServletResponse进行处理
- HttpServletResponse 到达客户端
4. Filter生命周期
4.1 filter 有三个重要方法
init() : 初始化参数,在Filter创建时调用,并且只调用一次
doFilter(): 拦截时调用,客户端发送和响应时调用
destroy(): 在销毁FIlter时调用
Filter的创建和销毁由web服务器来控制
当web服务器启动时,创建Filter实例对象,并调用init()方法,filter对象只会创建一次,因此init方法也只会执行一次。
拦截请求时,会执行doFilter方法,因此会执行多次。
当web服务器关闭时,会销毁Filter对象,会调用destroy方法
5. Filter调用的原理
Filter 是基于链式递归调用,如下两个图所示
使用代码模拟Filter的调用原理,使用两种方式来实现,计数器和移除方式
- 创建Filter接口
package pattern.chain;
public interface Filter {
void doFilter(FilterChain filter, String something);
}
- 创建FilterChain接口
package pattern.chain; public interface FilterChain { void add(Filter filter); void doFilter(String something); }
- 创建FirstFilter实现Filter接口
package pattern.chain; public class FirstFilter implements Filter { @Override public void doFilter(String request, String response, FilterChain filter) { System.out.println("before first..."); filter.doFilter(request, response); System.out.println("after first..."); } }
- 创建SecondFilter实现Filter接口
package pattern.chain; public class SecondFilter implements Filter { @Override public void doFilter(String request, String response, FilterChain filter) { System.out.println("befor second..."); filter.doFilter(request, response); System.out.println("after second..."); } } ```
- 创建ThirdFilter实现FIlter接口
package pattern.chain; public class ThirdFilter implements Filter { @Override public void doFilter(String request, String response, FilterChain filter) { System.out.println("before third filter ...."); filter.doFilter(request, response); System.out.println("after third filter ...."); } }
- FilterChain实现类的
基于移除方式实现package pattern.chain; import java.util.LinkedList; public class FilterChainImpl implements FilterChain { private LinkedList<Filter> filters = new LinkedList<>(); @Override public void add(Filter filter) { filters.add(filter); } public boolean hasNextFilter() { return filters.size() > 0; } public Filter nextFilter() { return filters.pop(); } @Override public void doFilter(String request, String response) { if(hasNextFilter()) { nextFilter().doFilter(request, response, this); } } }
基于计数实现方式
package pattern.chain;
import java.util.ArrayList;
import java.util.List;
public class FilterChainImpl implements FilterChain {
private List<Filter> list = new ArrayList<>();
private int index;
@Override
public void add(Filter filter) {
list.add(filter);
}
@Override
public void doFilter(String request, String response) {
if(index < list.size()) {
Filter filter = list.get(index);
index ++;
filter.doFilter(request, response, this);
}
}
}
- 测试调用,创建FilterChainMain类
package pattern.chain; public class FilterChainMain { public static void main(String[] args) { FilterChain filterChain = new FilterChainImpl(); filterChain.add(new FirstFilter()); filterChain.add(new SecondFilter()); filterChain.add(new ThirdFilter()); filterChain.doFilter(null, null); } }
结果打印
6 undertow与tomcat 的Filter实现
undertow 是基于计数实现Filter的调用,实现类是FilterHandler.FilterChainImpl 类
tomcat 是基于计数实现Filter的调用,实现类是ApplicationFilterChain