什么是Filter?

本文所说的Filter是JavaWeb中常见常使用的过滤器。Filter的作用是拦截前端发送给后端的请求,一般是用于权限过滤、日志记录、图片转换、加密、数据压缩等操作。
大致流程如下图所示:

初步了解Filter接口

Filter是过滤器的核心接口,其中定义了初始化方法、拦截请求后的要做的具体任务方法、销毁方法。

public interface Filter {//初始化方法,整个生命周期中只执行一次。//在init方法成功(失败如抛异常等)执行完前,不能提供过滤服务。//参数FilterConfig用于获取初始化参数public void init(FilterConfig filterConfig) throws ServletException;//执行过滤任务的方法,参数FilterChain表示过滤器链,doFilter方法中只有执行chain.doFilter()后才能调用下一个过滤器的doFilter方法//才能将请求交经下一个Filter或Servlet执行public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;//销毁方法,当移出服务时由web容器调用。整个生命周期中destroy方法只会执行一次//destroy方法可用于释放持有的资源,如内存、文件句柄等public void destroy();
}

拦截器使用例子

@WebFilter(urlPatterns = "/my")
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) {System.out.println("filter init...");}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("在这个方法里面完成权限认证、信息加密等操作");chain.doFilter(request, response); // 执行下一个过滤器doFilter方法。如果在执行此句之前就return返回,则请求到此结束。}@Overridepublic void destroy() {System.out.println("filter destroy...");}
}

Filter拦截器使用起来十分简单,只要我们自定义的过滤器类实现Filter接口,覆盖其中的init、doFilter、destroy方法即可。
使用上来说,过滤器的实现可以说是有手就行了。但是其中的具体实现逻辑,比如说Filter是在什么时候起作用的?为什么可以不断的层级调用?等等问题。作为Java工程师来说,在工作中运用如此频繁的组件,是时候应该详细了解一番了。

Filter的执行流程

详细的说,Filter的执行流程主要分为两个部分:

  • 初始化部分:对于定义好的Filter过滤器(例如上面自定义的MyFilter),会首先创建过滤器对象,并保存到过容器中,并调用其init方法进行初始化。

  • 执行部分:当匹配到相应的请求路径时,首先会对该请求进行拦截,执行doFilter中的逻辑,若不通过则该请求则到此为止,不会继续往下执行(此时通常会进行重定向或者转发到其他地方进行处理);若通过则继续执行下一个拦截器的doFilter方法,直到指定的过滤器都执行完doFilter后,便执行Servlet中的业务逻辑。

1. 初始化部分

首先来了解下Filter的初始化流程,就拿上面自定义的MyFilter类来作为例子讲解(为了讲解源码时候排除不必要的干扰,此后的源码解析内容只针对关键部分代码进行讲解)。

当我们定义好MyFilter类后,便开启Tomcat服务器,开始启动程序。
通过调试发现初始化Filter的入口是:StandardContext类的startInternal方法

@Override
protected synchronized void startInternal() throws LifecycleException {... // 省略不必要代码fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null); // 读取web.xml配置文件或者注解配置信息,创建并添加Filter... if (ok) {if (!filterStart()) { // 初始化Filter。若初始化成功则继续往下执行;若初始化失败则抛出异常,终止程序log.error(sm.getString("standardContext.filterFail"));ok = false;}}...
}

可以看到,原来filterStart方法才是真正初始化Filter的方法。
那么在看filterStart方法源码之前,我们先来了解下一些相关的重点属性(有助于之后的源码阅读):

// filterConfigs是一个HashMap,以键值对的形式保存数据(key :value = 过滤器名 :过滤器配置信息对象)
private HashMap<String, ApplicationFilterConfig> filterConfigs = new HashMap<>();
// filterDefs同时也是一个HashMap,其中保存的数据是(过滤器名 :过滤器定义对象)
private HashMap<String, FilterDef> filterDefs = new HashMap<>();

看下其中的FilterDef、ApplicationFilterConfig这两个类,再进一步了解上面的两个属性:

FilterDef:

/**
* 来看下官方解释:
* Web应用程序的过滤器定义的表示形式,如部署描述符中<filter>元素中的所示。
* 例如:
* <filter>
*   <filter-name>MyFilter</filter-name>
*   <filter-class>com.filter.MyFilter</filter-class>
* </filter>
*
* 说白了,这个FilterDef其实就是封装了配置信息中<filter>标签当中的元素
* 其中就有三个重点属性:filterName、filterClass、filter
*/
public class FilterDef implements Serializable {...private String filterName = null; // 过滤器名,对应的是<filter-name>中的内容private String filterClass = null; // 过滤器全限定类名,对应的是<filter-class>中的内容(用于反射创建过滤器对象)private transient Filter filter = null; // 真正的过滤器对象(如:MyFilter实例对象)...
}

ApplicationFilterConfig:

/**
* ApplicationFilterConfig类主要用于保存自定义Filter的一些配置信息,例如过滤器名、初始化参数、过滤器定义对象等等
*/
public final class ApplicationFilterConfig implements FilterConfig, Serializable {.../*** 构造方法*/ApplicationFilterConfig(Context context, FilterDef filterDef)throws ClassCastException, ClassNotFoundException, IllegalAccessException,InstantiationException, ServletException, InvocationTargetException, NamingException,IllegalArgumentException, NoSuchMethodException, SecurityException {super();this.context = context; this.filterDef = filterDef; // 由此可知,ApplicationFilterConfig类中其实定义了过滤器定义对象// 初始化真正的过滤器对象if (filterDef.getFilter() == null) {getFilter();} else {this.filter = filterDef.getFilter();getInstanceManager().newInstance(filter);initFilter();}}...
}

了解完上面的属性,我们再来研究filterStart方法到底做了什么:

public boolean filterStart() {if (getLogger().isDebugEnabled()) { // 日志相关getLogger().debug("Starting filters");}boolean ok = true;synchronized (filterConfigs) { // 初始化过滤器属于同步操作filterConfigs.clear(); // 在初始化前,先清空for (Entry<String,FilterDef> entry : filterDefs.entrySet()) { // 循环遍历过滤器定义对象集合(filterDefs初始化在哪?)String name = entry.getKey(); // 获取过滤器名if (getLogger().isDebugEnabled()) { // 日志相关getLogger().debug(" Starting filter '" + name + "'");}try {ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(this, entry.getValue()); // 创建过滤器配置对象filterConfigs.put(name, filterConfig); // 添加配置对象} catch (Throwable t) {t = ExceptionUtils.unwrapInvocationTargetException(t);ExceptionUtils.handleThrowable(t);getLogger().error(sm.getString("standardContext.filterStart", name), t);ok = false;}}}return ok;
}

此处,如果细心的朋友就会发现,filterStart方法中直接就拿filterDefs进行循环遍历获取过滤器名了。但是filterDefs是在哪里进行添加元素的呢?
回想一下,我们发现初始化过滤器的入口是StandardContext类中的startInternal方法,而在其中执行真正过滤器初始化方法前,还有一步:

fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null); // 读取web.xml配置文件或者注解配置信息,创建并添加FilterDef过滤器定义对象// 通过调试代码,可以找到其实是调用了ContextConfig类中configureContext方法,以下部分是该方法中的关键代码
for (FilterDef filter : webxml.getFilters().values()) { // 循环配置信息中的过滤器定义对象if (filter.getAsyncSupported() == null) {filter.setAsyncSupported("false");}context.addFilterDef(filter); // 将过滤器定义对象添加到容器中
}/**
* 最后发现fireLifecycleEvent方法最终调用的是StandardContext类中的addFilterDef方法
* 而参数filterDef正是容器context经过解析web.xml文件或者注解配置后创建的过滤器定义对象
* 但此时filterDef中的真正过滤器对象filter还未初始化,因此才会有之后的初始化过滤器方法
*/
public void addFilterDef(FilterDef filterDef) {synchronized (filterDefs) { // 同步添加过滤器定义对象filterDefs.put(filterDef.getFilterName(), filterDef); }fireContainerEvent("addFilterDef", filterDef);
}

明白了filterDefs的初始化,我们再回到filterStart方法,而此时执行到创建ApplicationFilterConfig过滤器配置对象:

/**
* 没错,就是调用这个构造方法创建的filterConfig
**/
ApplicationFilterConfig(Context context, FilterDef filterDef)throws ClassCastException, ClassNotFoundException, IllegalAccessException,InstantiationException, ServletException, InvocationTargetException, NamingException,IllegalArgumentException, NoSuchMethodException, SecurityException {super();this.context = context;this.filterDef = filterDef;// 现在重点来关注以下部分的代码// 从过滤器定义对象中获取真正的过滤器对象(正常来说,应该都是空。因为从之前filterDefs的添加元素逻辑来看,添加的过滤器定义对象中的过滤器对象都是空的)if (filterDef.getFilter() == null) { // 过滤器对象为空getFilter(); // 获取并初始化过滤器(此处没有进行接收结果,说明此处只是进行初始化)} else {this.filter = filterDef.getFilter(); // 绑定过滤器对象getInstanceManager().newInstance(filter);initFilter(); // 调用过滤器的init方法,初始化过滤器}
}

获取并初始化过滤器

Filter getFilter() throws ClassCastException, ClassNotFoundException, IllegalAccessException,InstantiationException, ServletException, InvocationTargetException, NamingException,IllegalArgumentException, NoSuchMethodException, SecurityException {if (this.filter != null) // 若ApplicationFilterConfig类中已存在过滤器对象,则直接返回return (this.filter);// 通过反射的方式创建过滤器对象,并绑定到配置对象的filter上String filterClass = filterDef.getFilterClass(); this.filter = (Filter) getInstanceManager().newInstance(filterClass);initFilter(); // 调用过滤器对象的init方法,初始化过滤器return (this.filter);
}

到此,过滤器对象也已经创建了,就差调用它的init方法初始化了:

private void initFilter() throws ServletException {if (context instanceof StandardContext && context.getSwallowOutput()) {try {SystemLogHandler.startCapture();filter.init(this);} finally {String capturedlog = SystemLogHandler.stopCapture();if (capturedlog != null && capturedlog.length() > 0) {getServletContext().log(capturedlog);}}} else {filter.init(this); // 终于看到了,调用了filter对象的init方法}// Expose filter via JMXregisterJMX();
}@WebFilter(urlPatterns = "/my")
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) { // 其实就是调用了这个我们自己实现的init方法System.out.println("filter init...");}...
}

那么过滤器的初始化部分就到此结束了。

我们来整理下逻辑,如果你的逻辑清晰的话,就可以明白过滤器初始化的这个部分,做了各种各样的事情,其实都是为了根据配置信息去创建filterConfig对象,并为它的filterDef和filter属性进行赋值,最后将其添加到filterConfigs中去。
换句话说,其实就是为了根据配置信息去创建过滤器配置对象,并初始化它的过滤器定义对象和真正的过滤器对象,最后将它加入到容器的过滤器配置映射表中去

为了加深对Filter初始化部分的源码理解,送出下图:

2. 执行部分

了解完Filter的初始化,说明在后端程序中已经存在有相应的过滤器了(Tomcat自带的,我们自定义的)。那么当请求访问到达后端的时候,Filter是如何工作的?

下面再来看调用Filter的方法入口StandardWrapperValve类中的invoke:

public final void invoke(Request request, Response response) throws IOException, ServletException {...ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet); // 创建并初始化过滤器链try {if ((servlet != null) && (filterChain != null)) { // 此处需要判断servlet和过滤器不为空。因为在执行完过滤器链中所有的过滤器doFilter方法后,就会轮到真正处理请求的servlet来处理if (context.getSwallowOutput()) {try {SystemLogHandler.startCapture();if (request.isAsyncDispatching()) { request.getAsyncContextInternal().doInternalDispatch();} else {filterChain.doFilter(request.getRequest(),response.getResponse());}} finally {String log = SystemLogHandler.stopCapture();if (log != null && log.length() > 0) {context.getLogger().info(log);}}} else {if (request.isAsyncDispatching()) {request.getAsyncContextInternal().doInternalDispatch();} else {filterChain.doFilter(request.getRequest(), response.getResponse()); // 执行过滤器链中的所有过滤器的doFilter方法}}}} catch(...){...}...
}

通过上面的源码,可以看到直接就通过创建的过滤器链执行其中过滤器的doFilter方法了。因此重点就在于这个过滤器链filterChain是如何创建的?

来看下ApplicationFilterFactory类的createFilterChain方法:

public static ApplicationFilterChain createFilterChain(ServletRequest request, Wrapper wrapper, Servlet servlet) {if (servlet == null) // 如果没有之后处理请求的servlet,那么即使有过滤器也是白搭,直接返回空return null;// 创建过滤器链ApplicationFilterChain filterChain = null;if (request instanceof Request) {Request req = (Request) request;if (Globals.IS_SECURITY_ENABLED) {filterChain = new ApplicationFilterChain(); // 安全启用的过滤器链,直接新建,不复用request请求中的过滤器链} else {filterChain = (ApplicationFilterChain) req.getFilterChain(); // 获取请求中的过滤器链(若是第一次访问,获取的过滤器链为空)if (filterChain == null) { // 过滤器链为空filterChain = new ApplicationFilterChain(); // 新建过滤器链req.setFilterChain(filterChain); // 加入request请求中,在之后可以进行复用}}} else {// Request dispatcher in usefilterChain = new ApplicationFilterChain();}filterChain.setServlet(servlet); // 在过滤器链中设置最后处理请求的servletfilterChain.setServletSupportsAsync(wrapper.isAsyncSupported());StandardContext context = (StandardContext) wrapper.getParent(); // 获取StandardContext容器// 这里又冒出来一个filterMaps,它又是怎么来的?FilterMap filterMaps[] = context.findFilterMaps(); // 获取过滤器映射对象if ((filterMaps == null) || (filterMaps.length == 0)) // 如果过滤器映射对象都不存在,或者没有映射信息,则说明没有自定义过滤器,则直接返回过滤器链return (filterChain);DispatcherType dispatcher = (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); // 获取当前request请求的类型String requestPath = null;Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);if (attribute != null){requestPath = attribute.toString(); // 请求地址(例如:/my)}String servletName = wrapper.getName(); // 获取最终处理请求的servlet名// 循环遍历过滤器映射对象数组,为过滤器链添加符合条件的过滤器for (int i = 0; i < filterMaps.length; i++) {if (!matchDispatcher(filterMaps[i] ,dispatcher)) { // 匹配请求类型,不匹配则跳过continue;}if (!matchFiltersURL(filterMaps[i], requestPath)) // 匹配请求地址,不匹配则跳过continue;ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); // 符合前两个匹配条件,则根据过滤器名在StandardContext容器中获取对应的过滤器配置对象if (filterConfig == null) { continue;}filterChain.addFilter(filterConfig); // 到这步终于明白,过滤器链中添加的并不是过滤器对象,而是过滤器配置对象}// 循环遍历过滤器映射对象数组,再次为过滤器链添加符合条件的过滤器for (int i = 0; i < filterMaps.length; i++) {if (!matchDispatcher(filterMaps[i] ,dispatcher)) { // 匹配请求类型,不匹配则跳过continue;}if (!matchFiltersServlet(filterMaps[i], servletName)) // 匹配过滤器对应的servlet名,不匹配则跳过continue;ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); // 符合前两个匹配条件,则根据过滤器名在StandardContext容器中获取对应的过滤器配置对象if (filterConfig == null) {continue;}filterChain.addFilter(filterConfig); // 添加对应的过滤器配置对象}// 到此,filterChain过滤器链已经将匹配的请求类型、请求路径、请求最终处理的servlet这三个条件的过滤器配置对象添加完毕,返回return filterChain;
}

当createFilterChain方法执行完后,一个完整的过滤器链filterChain就有了。
但是在过滤器链生成的过程中有个非常重要的角色:filterMap,以及createFilterChain方法中还有很多其他的看似不起眼的方法,听我接下来慢慢分析:

首先,我们先来看看这个filterMap是个什么东西:

FilterMap filterMaps[] = context.findFilterMaps(); // 从createFilterChain方法中的这句就可以知道,filterMap是从context容器来的/**
* 这个context容器其实就是我们一直说的StandardContext
* 然后点进来到findFilterMaps方法,发现它只是返回了filterMaps属性对象的asArray方法的结果
*/
@Override
public FilterMap[] findFilterMaps() {return filterMaps.asArray();
}// 因此,再来看这个filterMaps属性是个什么东西
// 原来又是ContextFilterMaps类的对象
private final ContextFilterMaps filterMaps = new ContextFilterMaps();/**
* 再点进来这个ContextFilterMaps类,发现原来它是StandardContext类中的一个静态final内部类
* 重点是其内部维护了一个FilterMap[]类型的数组,而且它的asArray方法也只是返回了这个数组
*/
private static final class ContextFilterMaps {... private FilterMap[] array = new FilterMap[0];...public FilterMap[] asArray() {synchronized (lock) {return array;}}...}
}

到此,可以知道StandardContext类的findFilterMaps方法返回的是,其内部类ContextFilterMaps中维护的一个FilterMap[]类型的数组。

但是对于filterMap的探索仍未结束,因为我们只知道它是一个FilterMap[]类型的数组,但是这个FilterMap是个什么类我们不知道,那还是继续看下吧:

/*** 来看下这个类的官方解释:* Web应用程序的过滤器映射的表示形式,如部署描述符中<filter-mapping>元素中的所示* 每个过滤器映射都必须包含过滤器名称以及URL模式或servlet名称* 例如以下配置:* <filter-mapping>  *    <filter-name>MyFilter</filter-name>  *    <url-pattern>/my</url-pattern> * </filter-mapping> * * 说白了,这个FilterMap就是封装了配置信息中<filter-mapping>标签中的元素* 其中还包含了两个重点属性:过滤器名、过滤器对应过滤的url*/
public class FilterMap extends XmlEncodingBase implements Serializable {...private String filterName = null; // 过滤器名,对应的是<filter-name>中的内容private String[] urlPatterns = new String[0]; // 过滤url,对应的是<url-pattern>中的内容(可配置多个<filter-mapping>匹配不同的url,因此是数组形式)...
}

终于,这个filterMap是个什么东西可以说是研究明白了。filterMap它其实就是个封装了配置映射信息中 过滤器名 和 对应过滤url 参数的对象数组

filterMap的定义搞清楚了,但是还不够。因为我们还不知道它是怎么初始化的?是在哪里把配置映射对象FilterMap加进去的?

接下来,给大家来说下这个filterMap是如何初始化的。(通过代码调试就ok了)在这里直接就和大家说了,大家应该还记得过滤器的第一阶段吧。是的,就是初始化阶段:

// 大家对这个方法还有印象吧,它就是初始化过滤器的入口方法(StandardContext类中的startInterval中调用)
// 针对于以下代码,我们之前的说法是:读取web.xml配置文件或者注解配置信息,创建并添加FilterDef过滤器定义对象
// 那么到了现在,其实全面一点的说法应该是:
// 1. 读取web.xml配置文件或者注解配置信息,创建并添加FilterDef过滤器定义对象
// 2. 同时也创建并添加FilterMap过滤器映射对象
fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null); // 以下同样是调用了ContextConfig类的configureContext方法,以下是关键代码
for (FilterMap filterMap : webxml.getFilterMappings()) { // 循环配置信息中的过滤器映射对象context.addFilterMap(filterMap); // 将过滤器映射对象添加到容器中
}/**
* 最终调用了StandardContext类中的addFilterMap方法
*/
@Override
public void addFilterMap(FilterMap filterMap) {validateFilterMap(filterMap); // 验证过滤器映射对象中的信息是否正确filterMaps.add(filterMap); // 添加到filterMaps中去fireContainerEvent("addFilterMap", filterMap);
}

到此,才可以说把filterMap这个东西的定义到初始化整个过程给研究明白了。

费了一番功夫,终于把这个filterMap给搞明白了。那么,再回头看下createFilterChain方法中被我们忽视的一些细节:

  • 获取过滤器配置对象:
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); // 说到底,还是根据过滤器名从容器中获取/*** findFilterConfig方法一看,其实就是从容器的filterConfigs中根据过滤器名获取到对应的配置对象* (忘记filterConfigs怎么来的话,回头去看初始化阶段)
*/
public FilterConfig findFilterConfig(String name) {return (filterConfigs.get(name));
}
  • 添加过滤器配置对象到过滤器链中:
filterChain.addFilter(filterConfig); // 添加过滤器配置对象/**
* 在此先介绍下ApplicationFilterChain过滤器链类的两个重要属性
*/
public final class ApplicationFilterChain implements FilterChain {...// filters数组,用于保存过滤器配置对象private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];// 表示filters中获取过滤器配置对象的索引位置,初始值为0。说明从头开始获取private int pos = 0;// filters中元素个数private int n = 0;// 扩容范围public static final int INCREMENT = 10;...
}/**
* 添加过滤器配置对象到filters中去
*/
void addFilter(ApplicationFilterConfig filterConfig) {for(ApplicationFilterConfig filter : filters) // 避免重复添加相同的过滤器配合对象if(filter==filterConfig)return;if (n == filters.length) { // 过滤器达到数组最大值ApplicationFilterConfig[] newFilters = new ApplicationFilterConfig[n + INCREMENT]; // 扩容(扩大10个长度)System.arraycopy(filters, 0, newFilters, 0, n);filters = newFilters;}filters[n++] = filterConfig; // 将filterConfig添加到filters末尾
}

到此,过滤器链filterChain的创建和初始化已经完成了。

那么终于来到过滤器的最后一步,执行过滤器链中的过滤器。让我们重新回到StandardWrapperValve类中的invoke方法:

filterChain.doFilter(request.getRequest(), response.getResponse()); // 执行过滤器链中的所有过滤器的doFilter方法(注意,这里调用的是过滤器链的doFilter方法,而不是过滤器的)@Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {if( Globals.IS_SECURITY_ENABLED ) {...} else {internalDoFilter(request,response); // 重点关注这个方法}
}/**
* 终于来真正执行过滤器doFilter的方法
*/
private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {if (pos < n) { // 获取位置 < 过滤器个数,说明还有过滤器未执行,继续获取ApplicationFilterConfig filterConfig = filters[pos++]; // 从filters头开始往后获取当中的过滤器配置对象try {Filter filter = filterConfig.getFilter(); // 获取真正的过滤器对象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); // 执行过滤器的doFilter方法}} 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; // 注意这里,直接返回,不执行下面的代码}// 如果代码执行到此,说明过滤器链中的所有过滤器已经执行完毕,并都通过// 开始执行相应servlet中的service方法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 pointif ((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); // 执行serlvet中的service方法}} 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);}}
}@WebFilter(urlPatterns = "/my")
public class MyFilter implements Filter {.../*** 经历了这么多,终于调用到这个doFilter方法了*/@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("doFilter...");chain.doFilter(request, response); // 在此处重新调用过滤器链的doFilter,执行下一个过滤器的doFilter方法}...
}

最后的最后,终于执行到过滤器的doFilter方法了!!!

说到底,其实这个过滤器执行阶段的话,就是首先通过过滤器链工厂创建过滤器链对象。然后根据配置信息的过滤器名和过滤路径,从容器中获取对应的过滤器配置对象,并将其加入到过滤器链对象中的过滤器数组中,最后将执行数组中包含的所有过滤器对象的doFilter方法。

最后为了加深理解,再基于第二阶段的源码分析,送出一图:

那么本文的再最后说一个细节,就是在过滤器的doFilter方法如果需要执行下一个过滤器的话,必须要调用 chain.doFilter(request, response)

正是基于以上的逻辑,我们通常会在Filter中做请求校验的业务。当校验通过,则继续执行下一个Filter,或者执行servlet处理请求;否则,就停止传递请求,返回错误信息给前端。

JavaWeb三大组件之一——Filter过滤器源码解析(全面手撕Filter源码,需要耐心看完)相关推荐

  1. JavaWeb三大组件(Servlet,Filter,Listener 自己整理,初学者可以借鉴一下)

    JavaWeb三大组件(Servlet,Filter,Listener 自己整理,初学者可以借鉴一下) Reference 转载于:https://www.cnblogs.com/Jeremy2001 ...

  2. SpringBoot定义三大组件Servlet,过滤器Filter,监听器Listener

    SpringBoot定义三大组件Servlet,过滤器Filter,监听器Listener 1.定义组件的配置类: com.example.mybatis2018.config.MyServletCo ...

  3. 【超详解】JavaWeb三大组件讲解

    文章目录 前言: 一.Servlet 二.Filter 三.Listener 总结 前言: JavaWeb三大组件指的是:Servlet.Filter.Listener,三者提供不同的功能,然而很多人 ...

  4. javaweb 三大组件之Severlet

    javaweb 三大组件之Severlet Servlet介绍 Javaweb三大组件 Servlet.Filter.Listener.今天我们就来了解下Servlet. 一:Servlet的作用: ...

  5. BAT高级架构师合力熬夜15天,肝出了这份PDF版《Android百大框架源码解析》,还不快快码住。。。

    前言 为什么要阅读源码? 现在中高级Android岗位面试中,对于各种框架的源码都会刨根问底,从而来判断应试者的业务能力边际所在.但是很多开发者习惯直接搬运,对各种框架的源码都没有过深入研究,在面试时 ...

  6. 手撕OpenCV源码之resize(INTER_AREA)

    手撕OpenCV源码之resize<INTER_AREA> resize在modules/imgproc/src/文件件中,首先看resize API的函数实现: void resize( ...

  7. Spring Cloud Gateway 源码解析(4)-- filter

    文章目录 绑定Filter HandlerMapping Filter GatewayFilterChain FilteringWebHandler GlobalFilter实例化 GatewayFi ...

  8. JavaWeb三大组件(ServletFilterListener)

    目录 一.Servlet 1.1概念 1.2步骤 1.3执行原理 1.4生命周期 1. 被创建:执行init方法,只执行一次 2. 提供服务:执行service方法,执行多次 3. 被销毁:执行des ...

  9. 【详解】Ribbon 负载均衡服务调用原理及默认轮询负载均衡算法源码解析、手写

    Ribbon 负载均衡服务调用 一.什么是 Ribbon 二.LB负载均衡(Load Balancer)是什么 1.Ribbon 本地负载均衡客户端 VS Nginx 服务端负载均衡的区别 2.LB负 ...

最新文章

  1. 【转】Java代码操作Redis的sentinel和Redis的集群Cluster操作
  2. python网络爬虫教程-教你从零开始学会写 Python 爬虫
  3. 如何在SAP云平台上使用MongoDB服务 1
  4. [Spring5]IOC容器_Bean管理_工厂Bean
  5. linux操作系统环境变量的配置
  6. java手动调用finalize_Java并手动执行finalize
  7. [摘录]第2章 中场谈判技巧
  8. 计算机专业的八字,生辰八字自动计算器软件 生辰八字在线计算器
  9. vld在MFC 中内存泄漏检测
  10. PHP有哪些基本数据类,PHP的基本数据类型
  11. vulnhub刷题记录(Pwn The Tron:1)
  12. 前端3D地球的实现方式
  13. 无人机基础知识:多旋翼无人机各模式控制框图
  14. QQ被盗后,如何找回好友
  15. AntV G2 Tooltip
  16. Android 节操视频播放器jiecaovideoplayer使用
  17. Coinversation Protocol (铸币协议)简版白皮书及网站
  18. php 时间戳与日期的转换
  19. mysql员工请假流程表字段_“员工请假”流程及在线表单开发示例
  20. 图灵计算机科学的奠基人英文,阿兰.图灵被认为是计算机科学的奠基人,他的主要贡献是:...

热门文章

  1. java mail 发送qq以及网易邮件
  2. ACM3108/ACM3128/ACM3129功放芯片动态调整升压延长音箱电池续航
  3. apm PDU IMSI RNC UE TMN
  4. 关于LED电视机视频编码H.264,MPEG4,MPEG2能支持哪些格式的视频文件
  5. LeetCode题解(1443):收集无向树中所有苹果的最少移动距离(Python)
  6. Kotlin-12-循环(for+repeat+list遍历)
  7. WPF 修改标题栏背景色(标题栏的最小化、最大化、关闭需要调一下)
  8. #研发解决方案#分布式抓取管理平台-魔镜
  9. 使用CloudFlare的WordPress站点应该用什么缓存?WP Super Cache可以吗?
  10. nes 红白机模拟器 第6篇 声音支持