过滤器是web开发中常用的组件,可以通过web.xml中的filter和filter-mapping标签来配置过滤器的相关信息。过滤器的功能有点类似Servlet,但是使用起来更加灵活。在Tomcat中,跟过滤器相关的接口主要有三个:Filter,FilterChain和FilterConfig。
其中Filter接口是web开发中比较常用的一个接口,只要通过实现这个接口,就可以实现自定义的过滤器。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方法用于初始化自定义过滤器,类似Servlet的init方法,FilterConfig 与ServletConfig也类似,除了能取到容器的环境类ServletContext对象之外,还能获取在filter 标签下配置的init-param 参数值。
每个请求进来都会调用doFilter方法,并在Servlet的service方法之前被调用。FilterChain 代表当前的整个请求链,所以通过FilterChain 的doFilter方法可以将请求继续传递下去,直到定义的过滤器都被执行到。如果想在某一步拦截这个请求,那么就不调用doFilter方法,也就是不让请求传递给下一个过滤器。
destroy方法在过滤器对象销毁时会被调用。
FilterChain接口表示过滤器链,接口中只定义了doFilter一个方法。
public interface FilterChain {
public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;
}
doFilter 方法的作用就是在过滤器之间传递请求。
FilterConfig接口中定义了获取Filter相关信息的方法,实现类是ApplicationFilterConfig。
public interface FilterConfig {
public String getFilterName();
public ServletContext getServletContext();
public String getInitParameter(String name);
public Enumeration getInitParameterNames();
}
为了让自定义的每个过滤器都能够执行,就需要调用ApplicationFilterChain的doFilter 方法,因为ApplicationFilterChain的类修饰符是final,因此这个类的所有方法及属性都是不可继承的,doFilter 方法不能被重写,只能使用Tomcat中提供的。doFilter 方法中调用internalDoFilter方法传递请求。
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = null;
try {
filter = filterConfig.getFilter();
support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
filter, request, response);
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege
("doFilter", filter, classType, args, principal);
args = null;
} else {
filter.doFilter(request, response, this);
}
}
}
略
servlet.service(request, response);
}
ApplicationFilterChain类中定义了一个ApplicationFilterConfig类型的数组,用于存放Servlet对象的所有过滤器。数组中的过滤器是在创建ApplicationFilterChain对象时添加的,根据所有定义的Filter的url-pattern 的值与当前请求的URL进行匹配,如果匹配成功则保存到filters数组中。internalDoFilter方法中的pos表示当前计数器,也就是当前执行到第几个过滤器了,n表示过滤器的总数。如果pos小于n,表示过滤器还没执行完,那么接着获取下一个过滤器,当前计数器的值会加1,直到值等于n。
当过滤器链中的所有过滤器都执行完了之后,就会执行Servlet的service方法。通过使用过滤器,可以使我们能更加灵活地控制请求流转。