Filters-Servlets(四)

导读:本篇文章讲解 Filters-Servlets(四),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

概述

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

Filter API

接下来主要介绍Filter相关的接口,包含Filter、FilterConfig、FilterChain。
Filter的实现必须继承javax.servlet.Filter接口。这个接口包含了Filter的3个生命周期:init、doFilter、destroy。
Servlet容器初始化Filter时,会触发Fiter的init的方法,一般来说是在应用开始时。也就是说,init方法并不是在该Filter相关的资源使用到时才初始化(并非懒加载),而且这个方法只调用一次,用于初始Fiter。init方法的定义如下:

void init(FilterConfig filterConfig);

注意:FilterConfig实例是有Servlet容器传入init方法中的。FilterConfig将在后面章节讲解。
当Servlet容器每次处理Filter相关的资源时,都会调用该Filter实例的doFilter方法。Filter的doFilter方法包含ServletRequest、ServletResponse、FilterChain这3个参数。

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

接下来,说明一下doFilter的实现中访问ServletRequest、ServletResponse。这也就意味着允许给ServletRequest增加属性或者增加Header。当然也可以修饰ServletRequest或者ServletResponse来改变它们的行为。
在Filter的doFilter的实现中,最后一行需要调用FilterChain中的doChain方法。注意doFilter方法里的第3个参数,就是filterChain的实例:

filterChain.doFilter(request, response);

一个资源可能需要被多个Filter关联到(更专业一点来说,这应该叫做Filter链条),这时Filter.doFilter()的方法将触发Filter链条中下一个Filter。只有在Filter链条中最后一个Filter里调用Filer.doFilter(),才会触发处理资源的Controller方法。
如果在Filter.doFilter()的实现中,没有在结尾处调用FilterChain.doFilter()的方法,那么该Request请求中止,后面的处理就会中断。
注意:FilterChain接口中,唯一的方法就是doFilter。该方法与Filter中的doFilter的定义是不一致的:在FilterChain中,doFilter方法只有两个参数,但在Filter中,doFilter方法有三个参数。
Filter接口中,最后一个方法时destroy,它的定义如下:

void destroy();

该方法在Servlet容器要销毁Filter时触发,一般在应用停止的时候进行调用。
除非Filter在部署描述中被多次定义到,否则Servlet窗口只会为每个Filter创建单一实例。由于Servlet/JSP的应用通常要处理用户并发请求,此时Filter实例需要同时被多个线程所关联到,因此需要非常小心的处理多线程问题。

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:
    第二个方法是getParameter。
    有两种方法可以配置Filter:一种通过WebFilter的Annotation来配置Filter,另一种是通过部署描述来注册。使用@WebFilter的方法,只需要在Filter的实现类中增加一个注解即可,不需要重复的配置部署描述符。当然,此时要修改配置参数,就需要重新构建Filter实现类了。换句话说,使用部署描述符意味着修改Filter配置只要修改一下文本文件就可以了。
    使用@WebFilter,你需要熟悉下面的参数,这些参数是在WebFilter的Annotation里定义的。所有参数都是可选的:
    在这里插入图片描述
    举个列子,下述@WebFilter标注配置了一个Filter,该名称为DataCompressionFilter,且适用于所有资源:
    @WebFilter(filterName=“DataCompressionFilter”, urlPatterns={“/*”})
    如果使用部署描述中的filter、filter-mapping元素定义,那么它的内容如下:
<filter>
	<filter-name>DataCompressionFilter</filter-name>
	<filter-class>
		the fully-qualified name of the filter class
	</filter-class>
	<filter-mapping>
		<filter-name>DataCompressionFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</filter>

Filter顺序

如果多个Filter应用于同一个资源,Filter的触发顺序非常重要,这时候就需要使用部署描述符来管理Filter;指定哪个Filter先被触发。例如:Filter1需要在Filter2前被触发。那么在部署描述符中,Filter1需要配置在Filter2之前:

<filter>
	<filter-name>Filter1</filter-name>
	<filter-class>
		the fully-qualified name of the filter class
	</filter-class>
</filter>
<filter>
	<filter-name>Filter2</filter-name>
	<filter-class>
		the fully-qualified name of the filter class
	</filter-class>
</filter>

通过部署描述之外的配置来指定Filter触发的顺序是不可能的。

小结

本章介绍了Filter API的相关内容,如Filter接口,FilterConfig接口、FilterChaing接口。通过本章内容,读者能够掌握如何实现一个Filter接口,并且通过@WebFilter的Annotate或者部署描述来配置它。
每个Filter仅有一个实现,因此如果需要保持或者改变Filter实现中的状态,就要考虑线程安全问题。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/100215.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!