之前在学习Java中功能增强的方法时经常说到过滤器,虽会用但是不知道为什么我们写一个类实现Filter接口就可以实现请求拦截了?现在以最常见的web容器Tomcat为例看看到底是为什么(Tomcat功能块很多,这里只看Filter这一部分)。
Tomcat的Filter是责任链模式的典型例子,我们可以定义多个Filter,在每个过滤器的doFilter方法中实现过滤逻辑并执行filterChain.doFilter(request,response).所以我们定义的Filter是由FilterChain来调用的,那是什么时候创建的FilterChain实例,它又是什么时候调用的filter呢?
先看FilterChain的定义:
final class ApplicationFilterChain implements FilterChain {
private static final ThreadLocal<ServletRequest> lastServicedRequest; **************
private static final ThreadLocal<ServletResponse> lastServicedResponse; **************
public static final int INCREMENT = 10;
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; ************
private int pos = 0;
private int n = 0;
private Servlet servlet = null; **************
... ...
}
它里面以ThreadLocal存储request和response,所以这个FilterChain应该是线程共享的,那它应该是在容器初始化的时候就创建出实例了
看tomcat的代码目录发现下面几个和Filter相关的实现类
image.png
FilterFactory中有初始化FilterChain的静态工厂方法createFilterChain。
说了这些,最重要的信息就是是FilterChain执行了我们的Filter,我们看它的doFilter方法:
private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
//如果filter还没执行完就执行剩下的filter
if (this.pos < this.n) {
//FilterChain中有个数组域存放了所有的Filter信息,按顺序遍历执行所有filter
ApplicationFilterConfig filterConfig = this.filters[this.pos++];
try {
//根据filter信息获取Filter实例
Filter filter = filterConfig.getFilter();
if (request.isAsyncSupported() && "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", Boolean.FALSE);
}
if (Globals.IS_SECURITY_ENABLED) {
Principal principal = ((HttpServletRequest)request).getUserPrincipal();
Object[] args = new Object[]{request, response, this};
SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal);
} else {
//执行filter的doFilter方法(在我们Filter的doFilter中调用filterChain.doFilter就会循环回来调用下一个Filter了)
filter.doFilter(request, response, this);
}
} catch(){... ...}
} else { //如果Filter全部执行完了就调用servlet的service方法 ************
try {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(request);
lastServicedResponse.set(response);
}
if (request.isAsyncSupported() && !this.servletSupportsAsync) {
request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", Boolean.FALSE);
}
if (request instanceof HttpServletRequest && response instanceof HttpServletResponse && Globals.IS_SECURITY_ENABLED) {
Principal principal = ((HttpServletRequest)request).getUserPrincipal();
Object[] args = new Object[]{request, response};
SecurityUtil.doAsPrivilege("service", this.servlet, classTypeUsedInService, args, principal);
} else {
this.servlet.service(request, response);
}
} catch(){... ...}
finally {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set((Object)null);
lastServicedResponse.set((Object)null);
}
}
}
}
从上面可以看出两个信息:1、FilerChain是怎么执行了所有的Filter的。2、Servlet是在Filter执行完后执行的。
所以容器在接收请求后会调用filterChain的doFilter方法,所有Filter执行完后会调用Servlet?
thinking:一个request过来是谁接受的?我们的服务器到tomcat容器再到应用服务?
网友评论