您的位置:首页 > 运维架构 > Tomcat

Tomcat 的 ApplicationFilterChain

2018-01-11 10:50 316 查看

概述

Tomcat的类ApplicationFilterChain是一个Java Servlet API规范javax.servlet.FilterChain的实现,用于管理某个请求request的一组过滤器Filter的执行。当针对一个request所定义的一组过滤器Filter执行完后,下一个doFilter()调用就会执行目标Servlet的方法service()。

需要注意的是,这里针对一个request所定义的一组过滤器Filter执行完后才会调用目标servlet实例的service()方法,并不是说调用目标servlet实例时,这组Filter的逻辑都执行完了,而是说他们都已经被调用起来之后才会最终调用servlet实例。

事实上,一个Filter可以被设计成既可以在目标servlet执行之前执行一段逻辑,也可以在目标servlet执行之后再执行另外一段逻辑。因此,在一个ApplicationFilterChain链执行到目标servlet实例的service()方法时,你可以认为此时所有Filter被设计在servlet执行之前执行的逻辑都执行完了,而所有Filter的被设计在servlet执行之后执行的逻辑都还尚未执行。

源代码分析

/*
* 此源代码摘自Tomcat版本 8.5.23
*/
package org.apache.catalina.core;

import java.io.IOException;
import java.security.Principal;
import java.security.PrivilegedActionException;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.Globals;
import org.apache.catalina.security.SecurityUtil;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.res.StringManager;

/**
* Implementation of javax.servlet.FilterChain used to manage
* the execution of a set of filters for a particular request.  When the
* set of defined filters has all been executed, the next call to
* doFilter() will execute the servlet's service()
* method itself.
*
* @author Craig R. McClanahan
*/
public final class ApplicationFilterChain implements FilterChain {

// Used to enforce requirements of SRV.8.2 / SRV.14.2.5.1
private static final ThreadLocal<ServletRequest> lastServicedRequest;
private static final ThreadLocal<ServletResponse> lastServicedResponse;

static {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest = new ThreadLocal<>();
lastServicedResponse = new ThreadLocal<>();
} else {
lastServicedRequest = null;
lastServicedResponse = null;
}
}

// -------------------------------------------------------------- Constants

public static final int INCREMENT = 10;

// ----------------------------------------------------- Instance Variables

/**
* Filters. 执行目标Servlet.service()方法前需要经历的过滤器Filter,初始化为0个元素的数组对象
*/
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];

/**
* The int which is used to maintain the current position
* in the filter chain.
* 用于记录过滤器链中当前所执行的过滤器的位置,是当前过滤器在filters数组的下标,初始化为0
*/
private int pos = 0;

/**
* The int which gives the current number of filters in the chain.
* 过滤器链中过滤器的个数(注意:并不是数组filters的长度),初始化为0,和filters数组的初始长度一致
*/
private int n = 0;

/**
* The servlet instance to be executed by this chain.
* 该过滤器链执行完过滤器后最终要执行的目标Servlet
*/
private Servlet servlet = null;

/**
* Does the associated servlet instance support async processing?
* 所关联的Servlet实例是否支持异步处理 ? 缺省为 false,表示缺省情况下不支持异步处理。
*/
private boolean servletSupportsAsync = false;

/**
* The string manager for our package.
*/
private static final StringManager sm =
StringManager.getManager(Constants.Package);

/**
* Static class array used when the SecurityManager is turned on and
* <code>doFilter</code> is invoked.
*/
private static final Class<?>[] classType = new Class[]{
ServletRequest.class, ServletResponse.class, FilterChain.class};

/**
* Static class array used when the SecurityManager is turned on and
* <code>service</code> is invoked.
*/
private static final Class<?>[] classTypeUsedInService = new Class[]{
ServletRequest.class, ServletResponse.class};

// ---------------------------------------------------- FilterChain Methods

/**
* Invoke the next filter in this chain, passing the specified request
* and response.  If there are no more filters in this chain, invoke
* the service() method of the servlet itself.
* 执行过滤器链中的下一个过滤器Filter。如果链中所有过滤
4000
器都执行过,
* 则调用servlet的service()方法。
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet exception occurs
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {

// 下面的if-else分支主要是根据Globals.IS_SECURITY_ENABLED是true还是false决定
// 如何调用目标逻辑,但两种情况下,目标逻辑最终都是 internalDoFilter(req,res)
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
try {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<Void>() {
@Override
public Void run()
throws ServletException, IOException {
internalDoFilter(req,res);
return null;
}
}
);
} catch( PrivilegedActionException pe) {
Exception e = pe.getException();
if (e instanceof ServletException)
throw (ServletException) e;
else if (e instanceof IOException)
throw (IOException) e;
else if (e instanceof RuntimeException)
throw (RuntimeException) e;
else
throw new ServletException(e.getMessage(), e);
}
} else {
internalDoFilter(request,response);
}
}

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++];
try {
// 找到目标 Filter 对象
Filter filter = filterConfig.getFilter();

if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
}
// 执行目标 Filter 对象的 doFilter方法,
// 注意,这里当前ApplicationFilterChain对象被传递到了目标
// Filter对象的doFilter方法,而目标Filter对象的doFilter在执行完自己
// 被指定的逻辑之后会反过来调用这个ApplicationFilterChain对象的
// doFilter方法,只是pos向前推进了一个过滤器。这个ApplicationFilterChain
// 和Filter之间反复调用彼此doFilter方法的过程一直持续直到当前链发现所有的
// Filter都已经被执行
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);
} else {
filter.doFilter(request, response, this);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
return;
}

// We fell off the end of the chain -- call the servlet instance
// 这里是过滤器链中所有的过滤器都已经被执行的情况,现在需要调用servlet实例本身了。
// !!! 注意 : 虽然这里开始调用servlet实例了,但是从当前方法执行堆栈可以看出,过滤器链
// 和链中过滤器的doFilter方法的执行帧还在堆栈中并未退出,他们会在servlet实例的逻辑
// 执行完后,分别执行完自己剩余的的逻辑才会逐一结束。
try {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(request);
lastServicedResponse.set(response);
}

if (request.isAsyncSupported() && !servletSupportsAsync) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Boolean.FALSE);
}
// Use potentially wrapped request from this point
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse) &&
Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res};
SecurityUtil.doAsPrivilege("service",
servlet,
classTypeUsedInService,
args,
principal);
} else {
servlet.service(request, response);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.servlet"), e);
} finally {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(null);
lastServicedResponse.set(null);
}
}
}

/**
* The last request passed to a servlet for servicing from the current
* thread.
*
* @return The last request to be serviced.
*/
public static ServletRequest getLastServicedRequest() {
return lastServicedRequest.get();
}

/**
* The last response passed to a servlet for servicing from the current
* thread.
*
* @return The last response to be serviced.
*/
public static ServletResponse getLastServicedResponse() {
return lastServicedResponse.get();
}

// -------------------------------------------------------- Package Methods

/**
* Add a filter to the set of filters that will be executed in this chain.
* 往当前要执行的过滤器链的过滤器集合filters中增加一个过滤器
* @param filterConfig The FilterConfig for the servlet to be executed
*/
void addFilter(ApplicationFilterConfig filterConfig) {

// Prevent the same filter being added multiple times
// 去重处理,如果已经添加进来则避免二次添加
for(ApplicationFilterConfig filter:filters)
if(filter==filterConfig)
return;

if (n == filters.length) {
// !!! 请注意:每次需要扩容时并不是增加一个元素空间,而是增加INCREMENT个,
// 这个行为的结果是filters数组的长度和数组中过滤器的个数n并不相等
ApplicationFilterConfig[] newFilters =
new ApplicationFilterConfig[n + INCREMENT];
System.arraycopy(filters, 0, newFilters, 0, n);
filters = newFilters;
}
filters[n++] = filterConfig;

}

/**
* Release references to the filters and wrapper executed by this chain.
*/
void release() {
for (int i = 0; i < n; i++) {
filters[i] = null;
}
n = 0;
pos = 0;
servlet = null;
servletSupportsAsync = false;
}

/**
* Prepare for reuse of the filters and wrapper executed by this chain.
*/
void reuse() {
pos = 0;
}

/**
* Set the servlet that will be executed at the end of this chain.
*
* @param servlet The Wrapper for the servlet to be executed
*/
void setServlet(Servlet servlet) {
this.servlet = servlet;
}

void setServletSupportsAsync(boolean servletSupportsAsync) {
this.servletSupportsAsync = servletSupportsAsync;
}

/**
* Identifies the Filters, if any, in this FilterChain that do not support
* async.
*
* @param result The Set to which the fully qualified class names of each
*               Filter in this FilterChain that does not support async will
*               be added
*/
public void findNonAsyncFilters(Set<String> result) {
for (int i = 0; i < n ; i++) {
ApplicationFilterConfig filter = filters[i];
if ("false".equalsIgnoreCase(filter.getFilterDef().getAsyncSupported())) {
result.add(filter.getFilterClass());
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tomcat servlet filter