Filter是拦截Request请求的对象:在用户的请求访 问资源前处理ServletRequest以及ServletResponse,它可 用于日志记录、加解密、Session检查、图像文件保护 等。通过Filter可以拦截处理某个资源或者某些资源。 Filter的配置可以通过Annotation或者部署描述来完成。 当一个资源或者某些资源需要被多个Filter所使用到, 且它的触发顺序很重要时,只能通过部署描述来配置。

一.Filter API

1. Filter 相关接口,包含Filter, FilterConfig, FilterChain

  Filter的实现必须继承javax.servlet.Filter接口。这个 接口包含了Filter的3个生命周期:init、doFilter、 destroy。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

  Servlet容器初始化Filter时,会触发Filter的init方 法,一般来说是在应用开始时。也就是说,init方法并 不是在该Filter相关的资源使用到时才初始化的,而且 这个方法只调用一次,用于初始化Filter。init方法的定 义如下:

oid init(FilterConfig filterConfig)

注意: FilterConfig实例是由Servlet容器传入init方法中的.

  当Servlet容器每次处理Filter相关的资源时,都会调 用该Filter实例的doFilter方法。Filter的doFilter方法包含 ServletRequest、ServletResponse、FilterChain这3个参 数。

  doFilter的定义如下:

void doFilter(ServletRequest request, ServletResponse response,FilterChain filterChain)

  接下来,说明一下doFilter的实现中访问 ServletRequet、ServletResponse。这也就意味着允许给 ServletRequest增加属性或者增加Header。当然也可以修 饰ServletRequest或者ServletRespone来改变它们的行 为。

  在Filter的doFilter的实现中,最后一行需要调用 FilterChain中的doFilter方法。注意Filter的doFilter方法 里的第3个参数,就是filterChain的实例:

filterChain.doFilter(request, response)

  一个资源可能需要被多个Filter关联到(更专业一 点来说,这应该叫作Filter链条),这时Filter.doFilter() 的方法将触发Filter链条中下一个Filter。只有在Filter链 条中最后一个Filter里调用的FilterChain.doFilter(),才会 触发处理资源的方法。

  如果在Filter.doFilter()的实现中,没有在结尾处调 用FilterChain.doFilter()的方法,那么该Request请求中 止,后面的处理就会中断。

注意: FilterChain接口中,唯一的方法就是doFilter。该方法与Filter中的 doFilter的定义是不一致的:在FilterChaing中,doFilter方法只有两个参 数,但在Filter中,doFilter方法有三个参数。

  Filter接口中,最后一个方法是destroy,它的定义 如下:

Void destroy()

  该方法在Servlet容器要销毁Filter时触发,一般在应 用停止的时候进行调用。

  除非Filter在部署描述中被多次定义到,否则Servlet 窗口只会为每个Filter创建单一实例。由于Serlvet/JSP的 应用通常要处理用户并发请求,此时Filter实例需要同 时被多个线程所关联到,因此需要非常小心地处理多线 程问题。

2. Filter配置

  当完成Filter的实现后,就可以开始配置Filter了。 Filter的配置需要如下步骤:

  • 确认哪些资源需要使用这个Filter拦截处理。
  • 配置Filter的初始化参数值,这些参数可以在Filter的 init方法中读取到;
  • 给Filter取一个名称。一般来说,这个名称没有什么 特别的含义,但在一些特殊的情况下,这个名字十 分有用。例如,要记录Filter的初始化时间,但这个 应用中有许多的Filter,这时它就可以用来识别Filter 了。

  FilterConfig接口允许通过它的getServletContext的 方法来访问ServletContext:

ServletContext getServletContext(

  如果配置了Filter的名字,在FilterConfig的 getFilterName中就可以获取Filter的名字。getFilterName 的定义如下:

java.lang.String getFilterName()

  当然,最重要的还是要获取到开发者或者运维给 Filter配置的初始化参数。为了获取这些初始化参数, 需要用到FilterConfig中的两个方法,第一个方法是 getParameterNames:

java.util.Enumeration<java.lang.String> getInitParameterNames()

  这个方法返回Filter参数名字的Enumeration对象。 如果没有给这个Filter配置任何参数,该方法返回的是 空的Enumeration对象。

  第二个方法是getParameter:

java.lang.String getInitParameter(java.lang.String parameterName)

  有两种方法可以配置Filter:一种是通过WebFilter 的Annotation来配置Filter,另一种是通过部署描述来注 册。使用@WebFilter的方法,只需要在Filter的实现类 中增加一个注解即可,不需要重复地配置部署描述。当 然,此时要修改配置参数,就需要重新构建Filter实现 类了。换句话说,使用部署描述意味着修改Filter配置 只要修改一下文本文件就可以了。

  使用@WebFilter,你需要熟悉下表中所列出来的 参数,这些参数是在WebFilter的Annotation里定义的。 所有参数都是可选的。

WebFilter的属性
属性 描述
asyncSupported Filter是否支持异步操作
description Filter的描述
dispatcerTypes Filter所生效范围
displayName Filter的显示名
filterName Filter的名称
initParams Filter的初始化参数
largeIcon Filter的大图名称
servletName Filter所生效的Servlet名称
smallIcon Filter的小图名称
urlPatterns Filter所生效的URL路径
value Filter所生效的URL路径

 

3. 示例1: 日志 Filter

  作为第1个例子,将做一个简单的Filter:在app09a 的应用中把Request请求的URL记录到日志文本文件 中。日志文本文件名通过Filter的初始化参数来配置。 此外,日志的每条记录都会有一个前缀,该前缀也由 Filter初始化参数来定义。通过日志文件,可以获得许 多有用的信息,例如在应用中哪些资源访问最频繁; Web站点在一天中的哪个时间段访问量最多。

   这个Filter的类名叫LoggingFilter。 一般情况下,Filter的类名都以*Filter结尾。

 

 

4.

 

二.

1.

2.

3.

4.

 

三.

1.

2.

3.

4.

 

四.

1.

2.

3.

4.

 

五.

1.

2.

3.

4.

 

六.

1.

2.

3.

4.

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄