【Tomcat】Filter 原理

环境:tomcat 8.0.28

Filter 原理

本文主要介绍

  • filter 的配置方式与加载过程
  • 每次请求,filter 是如何配合工作的

filter 配置与加载

配置

目前已知两种配置 Filter 的方法:

  • web.xml 中配置 <filter>
  • @WebFilter

一般配置都会有两个部分:

  • filter 具体包括 filter class 、 filter name 及 一些属性

    web.xml 配置中指的是 <filter>

    @WebFilter 配置中包含被注解的类,和注解中的一些属性

  • filter mapping 包括 filter name、URL Pattern

    web.xml 配置中指的是 <filter-mapping>

    @WebFilter 配置指的是 valueurlPatterns

    这里注意 valueURLPattern 虽然功能一样,但是不能同时配置,否则会报错

其实这两部分是分开存放的,因为配置的时候他俩总是同时出现,错觉让我们认为他俩是一个整体,并且 filter-mapping 是可以配置多个的,下面我们解释下这两个东西是如何实现的:

加载

filter 的具体信息被加载到 StandardContext.filterDefs 中,filter mapping 被存放到 StandardContext.filterMaps 中 ,初始化过程:

  • org.apache.catalina.startup.ContextConfig.configureContext(WebXml webxml)

    // 设置 filter
    for (FilterDef filter : webxml.getFilters().values()) {
        if (filter.getAsyncSupported() == null) {
            filter.setAsyncSupported("false");
        }
        context.addFilterDef(filter);
    }
    
    // 设置 filter mapping
    for (FilterMap filterMap : webxml.getFilterMappings()) {
        context.addFilterMap(filterMap);
    }

读取 @WebFilter 注解的 filter

org.apache.catalina.startup.ContextConfig.webConfig() 函数中每个步骤注释的很明确:

// Step 4. Process /WEB-INF/classes for annotations and @HandlesTypes matches
if (ok) {
    WebResource[] webResources =
            context.getResources().listResources("/WEB-INF/classes");

    for (WebResource webResource : webResources) {
        processAnnotationsWebResource(webResource, webXml,
                webXml.isMetadataComplete());
    }
}

processAnnotationsStream(InputStream is, WebXml fragment, boolean handlesTypesOnly) 中处理了三个注解:@WebServlet, @WebFilter, @WebListener

这里保留一个疑问

ApplicationFilterRegistration.addMappingForUrlPatterns
这里添加了一个filter (FilterMap[filterName=Tomcat WebSocket (JSR356) Filter, urlPattern=/*])

不知道作用是什么

初始化 FilterChain

每次请求时,都要创建一个 FilterChain ,用来层层过滤、处理这次请求

一般见到 Chain 就知道这里运用了 责任链 模式,所以通过打断点,可以定位到 doFilter 的源头

filter.doFilter(request, response, this)
|
...
|
filterChain.doFilter(request, response)

filterChain.doFilter(request, response) 就是 责任链 开始的位置,顺藤摸瓜找到 filterChain 创建的位置:org.apache.catalina.core.StandardWrapperValve.invoke(Request request, Response response) -> ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

查看 ApplicationFilterChain 源码可知 FilterChain 的具体初始化过程

Tips

  • 在 SprintBoot 中使用 @WebServlet@WebFilter@WebListener,需要在 Application.class上加注解 @ServletComponentScan ,这里初始化 filter 的过程在 org.apache.catalina.core.ApplicationFilterConfig.initFilter(),是跟上面有区别的

    详细见:

    参考:

    Spring Boot 过滤器、监听器

  • 如果想让 filter 交给 spring 管理(即在 filter 中注入 bean),如下:

    <filter>
        <filter-name>${filter.displayName}</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>${filter.beanName}</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>${filter.displayName}</filter-name>
        <url-pattern>${filter.urlPattern}</url-pattern>
    </filter-mapping>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值