过滤器是一套java组件,用于在请求—>资源—>应答的这一过程中即时转换处理负载和头信息。

本章讲述了Servlet 2.4 API中一些类和方法,这些类和方法提供了一套轻量级框架用于过滤动态和静态内容。它讲述了web应用下如何配置过滤器、指定过滤器的实现类。

servlet过滤器的API会在SRV.14的“javax.servlet”章节提供,而其配置语法会在SRV.13章“部署描述符”的语法中讲解。读者阅读本章的同时也应该参考下对应的章节内容。

SRV.6.1    什么是过滤器

过滤器是一段用于转换HTTP请求、响应和头信息的可重用代码段。它不能创建响应对象,一般只用于修改或适配请求和响应过程中的资源处理。

过滤器可以处理动态或静态内容,在本章里,动态或静态内容主要涉及web资源。

开发人员主要在以下场景下使用过滤器:

1. 请求之前访问资源

2. 访问资源之前对请求做处理

3. 通过修改请求的头信息和信息体来封装一个自定义版本的请求对象

4. 通过修改响应的头信息和信息体来提供一个自定义版本的响应对象

5. 在过滤器调用时插入对指定资源的访问请求

6. 通过零到多个指定顺序的过滤器来操作servlet和静态内容

SRV.6.1.1    常见过滤器示例

• 授权过滤器

• 日志和审计过滤器

• 图像转换过滤器

• 数据压缩过滤器

• 加密过滤器

• 令牌过滤器

• 触发资源访问事件的过滤器

• XML内容转换过滤器

• MIME-type 内容链过滤器

• 缓存过滤器

SRV.6.2    主要概念

过滤器模式的主要概念在本章描述。

开发人员通过实现javax.servlet.Filter接口然后提供一个公共无参构造方法来创建过滤器。它会被打包进Web压缩包,正如构成web应用的静态内容和servlet一样。过滤器通过部署描述符中的<filter>元素进行声明。一个或一组过滤器然后通过定义<filter-mapping>元素来配置如何被调用。这个配置通过把过滤器映射到特定的servlet上来完成,或者把一组serlvet和静态内容映射到一个URL模式的过滤器上。

SRV.6.2.1    过滤器的生命周期

在部署应用系统之后容器访问web资源之前,容器必须定位用于访问web资源的所有过滤器。容器必须确保每一个过滤器在调用init(FilterConfig config)方法之后被正确的初始化。过滤器可以抛出异常表示它无法正常工作,如果异常是UnavailableException类型,容器必须检查它的isPermanect属性并可能在一段时间后重试这个过滤器。

一个过滤器实例只会被同一个容器的同一个JVM初始化一次容器负责提供过滤器的config对象,正如在部署描述中声明的那样,另外提供对ServletContext的引用和一系列初始化参数。

当容器收到传入的请求时,它通过doFilter方法调用过滤器列表中的第一个过滤器实例,并传入ServletRequest和ServletResponse,以及容器使用的FilterChain对象的引用。

过滤器的doFilter方法通常实现于以下模式里:

步骤1:检查请求头信息

步骤2:用自定义实现的ServletRequest或HttpServletRequest来封装请求对象,用于修改请求头或信息体。

步骤3:用自定义实现的ServletResponse或HttpServletResponse来封装响应对象,用于修改响应头或信息体。

步骤4:过滤器可能会调用过滤器链上的下一个实体对象,它可以是另一个过滤器,若本身已是最后一个过滤器节点,那下一个实体就是目标web资源。这个调用过程由FilterChain对象的doFilter方法完成,同时也会传递被调用的请求和响应对象。

容器提供的doFilter方法的过滤器链实现,必须定位下一个实体并调用对应的doFilter方法,并随之传递合适的请求和响应对象。

换句话说,过滤器链可以通过不调用下一个实体对象来阻塞请求的处理流程,留下的过滤器负责填充输出响应对象。

步骤5:下一个责任链实体调用之后,过滤器可以检查响应头信息。

步骤6:必要情况下过滤器可以抛出异常以示发生错误。如果过滤器在doFilter执行期间抛出UnavailableException,容器就不必再尝试继续处理剩下的流程。如果异常未标记为永久性的话,那可以等一段时间后再重试整个过滤器链。

步骤7:链条上的最后一个过滤器被调用之后,下一个被访问对象会是目标servlet或者链条末端的资源。

步骤8:容器删除一个过滤器的实例之前,必须先调用过滤器的destroy方法,用以释放所有的占用资源并执行清理操作。

SRV.6.2.2    封装请求和响应

过滤器的本质就是对请求或响应的封装,以便于能重写对应的行为方式去执行些过滤任务。在此模式下,开发人员不但负责重写请求和响应对象已存在的方法,而且还要提供新的API集给链条上接下来的其他过滤器和web资源。例如,开发人员可能想增强响应对象的输出能力,像允许DOM对象输出到客户端的API之类的情形。

为了支持这些过滤器,容器必须满足以下需求。当过滤器调用doFilter方法时,容器必须确保请求和响应对象在整个责任链条上始终一致。

这些需求也同样适用于RequestDispatcher.forward或RequestDispathcer.include,当他们想封装请求和响应对象时。

SRV.6.2.3    过滤器环境

一组初始化参数可以通过部署描述符中的<init-params>元素与过滤器关联起来。过滤器在运行时可以通过getInitParameter和getInitParameterNames方法来访问这些名值对。另外,FilterConfig提供了一条访问web应用系统的ServletConfig的途径。

SRV.6.2.4    Web应用中的过滤器配置

一个过滤器对应于部署描述符下的一个<filter>元素,在此元素中,开发人员可以声明以下内容:

• filter-name:  用于映射过滤器到一个servlet或URL下
• filter-class: 由容器用于标识唯一的过滤器类
• init-params: 过滤器的初始化参数

必要情况下,开发人员还能指定图标、文本描述和工具封装时使用的显示名。容器必须精确地对每一个过滤器的声明对应初始化一个Java类实例。如果两个过滤器声明指定了同一个Java类,那么容器就会对应的为这两个过滤器分别初始化一份Java类。

示例:

<filter>
    <filter-name>Image Filter</filter-name>
    <filter-class>com.acme.ImageServlet</filter-class>
</filter>

部署描述符一旦声明一个过滤器,对应的就会使用<filter-mapping>元素定义配套的servlet或静态资源。过滤器通过<servlet-name>元素和某个servlet关联起来。例如,以下代码把Image Filter映射到了ImageServlet这个servlet上:

<filter-mapping>
    <filter-name>Image Filter</filter-name>
    <servlet-name>ImageServlet</servlet-name>
</filter-mapping>

过滤器还可以通过<url-pattern>元素和一组serlvet或静态内容建立对应的关联关系:

<filter-mapping>
    <filter-name>Logging Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

这个例子里Loggin Filter会被用于所有的servlet和静态页面,因为每一个请求URL都和’/* ’相匹配。

当使用<url-pattern>方式处理<filter-mapping>元素时,容器必须检测<url-pattern>是否匹配请求的URL。

容器按照以下先后顺序编译过滤器链,用以处理对应的请求URI:

1. 首先,按照部署描述符中出现的先后顺序,<url-pattern>依次匹配过滤器映射。

2. 下一步,按照部署描述符中出现的先后顺序,<servlet-name>依次匹配过滤器映射。

这个需求意味着当容器收到请求时按照以下说明依次处理:

按照“映射规范”标识出目标Web资源。

若通过servlet名和web资源匹配到的过滤器有<servlet-name>,容器会按照部署描述符中出现的先后顺序依次编译创建对应的过滤器责任链。最后一个过滤器对应于最后一个<servlet-name>,并且它会用于调用最终的web资源。

若使用<url-pattern>模式的过滤器匹配到了请求的URI,容器按照过滤器在部署描述符中出现的先后顺序依次编译创建对应的过滤器责任链。过滤器链条最后一个过滤器是部署描述符中这个请求最后一个<url-pattern>匹配的过滤器。链条中的最后一个过滤器调用<servlet-name>匹配链条中的第一个过滤器,如果没有,就调用目标web资源。

专业一点来说高性能web容器都应该缓存过滤器责任链,这样一来就不用每次请求时都进行对应的计算了。

SRV.6.2.5    过滤器和请求分发器

个人理解上尚有不完善,待译。。。

文档信息

Servlet 2.4 规范之第七篇:过滤器的更多相关文章

  1. Servlet 2.4 规范之第六篇:响应

    响应对象封装了服务端返回给客户端的所有信息.在HTTP协议中,这些信息通过HTTP头和消息体传送. SRV.5.1    缓冲 出于效率考量,servlet容器可以缓冲输出数据,但这并非强制要求.常见 ...

  2. Servlet 2.4 规范之第五篇:请求

    request对象封装了来自客户端的所有请求信息.在HTTP协议中,客户端发给服务端的所有信息都是通过request对象的请求头和请求体来传送的.           SRV.4.1    HTTP协 ...

  3. Servlet 2.4 规范之第四篇:Servlet上下文

    SRV.3.1    ServletContext接口说明 ServletContext接口定义了运行servlet的web应用中和servlet相关的视图信息.容器提供者负责提供ServletCon ...

  4. Servlet 2.4 规范之第三篇:Servlet生命周期

        SRV.2.3    Servlet生命周期 servlet有着定义良好且明确的生命周期,它定义了servlet以怎样的方式加载和实例化.初始化.怎样处理客户端请求.以及怎样停止服务.生命周期 ...

  5. javaWeb核心技术第七篇之HTTP、Tomcat、Servlet、Request和Response

    - Web服务器 - 概念: - web资源: "英文直译"网"的意思 资源:一切数据文件 web资源:通过网络可以访问到的资源,通常指的是一切放在服务器上的文件&quo ...

  6. 解剖SQLSERVER 第七篇 OrcaMDF 特性概述(译)

    解剖SQLSERVER 第七篇  OrcaMDF 特性概述(译) http://improve.dk/orcamdf-feature-recap/ 时间过得真快,这已经过了大概四个月了自从我最初介绍我 ...

  7. JBoss和Tomcat版本、及Servlet、JSP规范版本对应一览 【转】

    原文地址:http://blog.csdn.net/hills/article/details/40896357 JBoss和Tomcat版本.及Servlet.JSP规范版本对应一览 JBossAS ...

  8. 第七篇 :微信公众平台开发实战Java版之如何获取微信用户基本信息

    在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的.对于不同公众号,同一用户的openid不同). 公众号可通过本接口来根据O ...

  9. 第七篇 Replication:合并复制-订阅

    本篇文章是SQL Server Replication系列的第七篇,详细内容请参考原文. 订阅服务器就是复制发布项目的所有变更将传送到的服务器.每一个发布需要至少一个订阅,但是一个发布可以有多个订阅. ...

随机推荐

  1. laravel5.5配置信息

    目录 1 环境配置 1.1 检索环境配置 1.2 确定当前环境 2 访问配置值 3 配置缓存 4 维护模式 配置文件在config目录下,为了便于不同人员的开发,我们可以使用不同的.env文件来配置各 ...

  2. 《Cracking the Coding Interview》——第18章:难题——题目3

    2014-04-29 01:02 题目:从m个整数里随机选出n个整数,要求等概率. 解法:和洗牌的算法类似,每次随机抽出一个数,抽n次即可.时间复杂度O(m * n),空间复杂度O(m). 代码: / ...

  3. python-压缩解压

    压缩解压包 #导入模块 import zipfile #新建压缩包并将db与ooo.xml压缩到文件中 z = zipfile.ZipFile('laxi.zip','w') z.write('db' ...

  4. RPG游戏黑暗之光

    1.设置默认鼠标光标 PlayerSettings → Default Cursor 下设置 2.为人物创建单一类 为人物创建了PlayerAnimation.cs.PlayerDir.cs.Play ...

  5. django-settings里redis连接与缓存配置

    # Django-redis的缓存配置 CACHES = { "default": { "BACKEND": "django_redis.cache. ...

  6. Day1 Toast/Menu/Intent传递数据

    ** --------------->未经允许,禁止转载<----------------** 今天是我读<第二行代码>的第一天,也是我第一次开始写CSDN博客,之前的笔记都在 ...

  7. 深入探讨ui框架

    深入探讨前端UI框架 1 前言 先说说这篇文章的由来 最近看riot的源码,发现它很像angular的dirty check,每个component ( tag )都保存一个expressions数组 ...

  8. [转] Linux命令行编辑常用键

    ctrl + a 将光标移动到命令行开头相当于VIM里shift+^ ctrl + e 将光标移动到命令行结尾处相当于VIM里shift+$ ctrl + 方向键左键 光标移动到前一个单词开头 ctr ...

  9. Java Web Action DAO Service层次理解

    参考来源:http://blog.csdn.net/inter_peng/article/details/41021727 1. Action/Service/DAO简介: Action是管理业务(S ...

  10. iOS如何隐藏状态栏,包括网络标志、时间标志、电池标志等

    我们在开发App的时候,在遇到有状态栏时,NavigationBar上面的按钮,是极难点击的,所以这个时候,最好我们能够人为的隐藏掉状态栏. 如果一直需要隐藏的话,直接在info.plist里面,添加 ...