【Tomcat】Filter 原理

来源:互联网 发布:安卓开发艺术探索源码 编辑:程序博客网 时间:2024/05/17 04:23

环境: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)

    // 设置 filterfor (FilterDef filter : webxml.getFilters().values()) {    if (filter.getAsyncSupported() == null) {        filter.setAsyncSupported("false");    }    context.addFilterDef(filter);}// 设置 filter mappingfor (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 matchesif (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(),是跟上面有区别的

    详细见:

    • Scanning for Servlets, Filters, and listeners

    • Add Servlets, Filters, and Listeners using classpath scanning

    参考:

    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>
1 0
原创粉丝点击