最近好多功能都是用Filter实现的,突然想到自己还没看过Filter运行的源码,
今天记录一下,以tomcat源码实现为例.
org.apache.catalina.core.ApplicationFilterChain是javax.servlet.FilterChain
的一个具体实现.
看一下主要执行过程,doFilter(ServletRequest request, ServletResponse response)
源码和注释如下:
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
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);//实际处理方法
}
}
看一下internalDoFilter(request,response)方法:
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
//pos当前Filter在数组中的位置,n当前Filter总数
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();//当前Filter
if (request.isAsyncSupported() && "false".equalsIgnoreCase(//异步支持设置
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
}
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);//执行当前Filter
}
} 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;
}
//当前请求的所有Filter已经完成执行,开始执行Servlet的service方法
try {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {//封装相同请求,设置到ThreadLocal中
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);//执行servlet服务
}
} 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);
}
}
}
好了,源码看完了,说一点其他的,
从源码中我们看出,当执行完FilterChain后才会执行servlet的service方法,
大家也知道,springmvc提供了拦截器功能,
拦截器功能是在DispatchServlet中HandlerMapping中配置的拦截器链,
那么他们的执行顺序是,Filter->拦截器,也就是如果有路径不被DispatchServlet拦截,那么只能用Filter进行过滤了.