`
roundlight
  • 浏览: 66492 次
  • 性别: Icon_minigender_1
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论
阅读更多

1、Servlet Filter概述

  凡是开发过J2EE的web application的人员都知道,经常需要处理以下几种情况:

   访问特定资源(Web 页、JSP 页、servlet)时的身份认证

   应用程序级的访问资源的审核和记录

   应用程序范围内对资源的加密访问,它建立在定制的加密方案基础上

   对被访问资源的及时转换, 包括从 servlet 和 JSP 的动态输出

  

  在servlet2.3之前这些功能处理是很难实现的,但是Java Servlet 2.3 规范新增了不少激动人心的功能,其中之一便是过滤器(Filter),其实这就是我们所说的管道和过滤器体系架构在J2EE中的应用实践. 通过使用该模式使得Web Application开发者能够在请求到达Web资源之前截取请求,在处理请求之后修改应答。其结构图如下:

 

500){this.resized=true;this.style.width=500;}" align=center vspace=1 border=1>

 

  一个执行过滤器的Java 类必须实现javax.servlet.Filter 接口。这一接口含有三个方法:

  init(FilterConfig):这是容器所调用的初始化方法。它保证了在第一次 doFilter() 调用前由容器调用。它能获取在 web.xml 文件中指定的filter初始化参数。

  doFilter(ServletRequest, ServletResponse, FilterChain):这是一个完成过滤行为的方法。它同样是上一个过滤器调用的方法。引入的 FilterChain 对象提供了后续过滤器所要调用的信息。

  destroy():容器在销毁过滤器实例前,doFilter()中的所有活动都被该实例终止后,调用该方法。

 

500){this.resized=true;this.style.width=500;}" align=center vspace=1 border=1>

 

  2、Filter链介绍

  所有过滤器都服从调用的过滤器链,并通过定义明确的接口得到执行。WebApplication可以指定许多过滤器来完成相关的工作.那么它们就组成一个过滤器链来完成相应的工作.其结构如下图:

 

500){this.resized=true;this.style.width=500;}" align=center vspace=1 border=1>

 

  3、例子

  3.1 简单filter

  在PetStore1.3.1中的就存在两个Filter过滤器.其中一个过滤器,完成字符集的编码的转化,如大家经常遇到的汉字编码问题,你只需配置为GBK即可.它从Web.xml之中读取这些参数的配置信息,然后进行编码的转化.另一个是安全校验Fliter,它负责进行安全检查哪些页面可以进行,哪些不可。它们组成一个Filter链,结构图和实现代码如下:

 

500){this.resized=true;this.style.width=500;}" align=center vspace=1 border=1>

 

public class EncodingFilter implements Filter {

 

 private FilterConfig config = null;

 // default to ASCII

 private String targetEncoding = "ASCII";

 public void init(FilterConfig config) throws ServletException {

  this.targetEncoding = config.getInitParameter("encoding");

 }

 //在过滤器中实现字符集编码转化

 public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain chain)

 throws IOException, ServletException {

 

  HttpServletRequest request = (HttpServletRequest)srequest;

  request.setCharacterEncoding(targetEncoding);

  // move on to the next

  chain.doFilter(srequest,sresponse);

 }

 public void destroy() {

  .................

 }

}

public class SignOnFilter implements Filter {

 public void init(FilterConfig config) throws ServletException {

  this.config = config;

  URL protectedResourcesURL = null;

  try {

   protectedResourcesURL = config.getServletContext().getResource("/WEB-INF/signon-config.xml");

   ...............

  } catch (java.net.MalformedURLException ex) {

   System.out.println("SignonFilter: malformed URL exception: " + ex);

  }

 }

 public void destroy() {

  config = null;

 }

 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

 throws IOException, ServletException {

  ........

 }

}

  容器通过 Web 应用程序中的配置描述符 web.xml 文件解析过滤器配置信息。有两个新的标记与过滤器相关:<filter> 和 <filter-mapping>。<filter> 标记是一个过滤器定义,它必定有一个 <filter- name> 和 <filter-class> 子元素。<filter-name> 子元素给出了一个与过滤器实例相关的名字。<filter-class> 指定了由容器载入的实现类。您能随意地包含一个 <init-param> 子元素为过滤器实例提供初始化参数。<filter-mapping> 标记代表了一个过滤器的映射,指定了过滤器会对其产生作用的 URL 的子集。

<!-- Encoding Filter Declaration Start -->

 

<filter>

 <filter-name>EncodingFilter</filter-name>

 <display-name>Encoding Filter</display-name>

 <description>no description</description>

 <filter-class>com.sun.j2ee.blueprints.encodingfilter.web.EncodingFilter</filter-class>

 <init-param>

  <param-name>encoding</param-name>

  <param-value>UTF-8</param-value>

 </init-param>

</filter>

<!-- Encoding Filter Declaration End -->

<!-- Signon Filter Declaration Start -->

<filter>

 <filter-name>SignOnFilter</filter-name>

 <display-name>SignOn Filter</display-name>

 <description>no description</description>

 <filter-class>com.sun.j2ee.blueprints.signon.web.SignOnFilter</filter-class>

</filter>

<!-- Signon Filter Declaration End -->

<!-- Encoding Filter Mapping Start-->

<filter-mapping>

 <filter-name>EncodingFilter</filter-name>

 <url-pattern>/*</url-pattern>

</filter-mapping>

<!-- Encoding Filter Mapping End -->

<!-- Signon Filter Mapping Start-->

<filter-mapping>

 <filter-name>SignOnFilter</filter-name>

 <url-pattern>/*</url-pattern>

</filter-mapping>

<!-- Signon Filter Mapping End -->

  3.2 复杂的filter

  上面是petstore的例子,演示了通过Fliter修改字符编码和安全认证的功能。下面提供一个示例演示通过修改返回数据(通过过滤器把response的字符串变成大写)。

public class UCaseResponse extends HttpServletResponseWrapper {

 

 public UCaseResponse(HttpServletResponse response) {

  super(response);

 }

 public PrintWriter getWriter() throws IOException {

  return new UCaseWriter(super.getWriter());

 }

}

public class UCaseWriter extends PrintWriter {

 public UCaseWriter(Writer out) {

  super(out);

 }

 public void write(int c) {

  super.write(Character.toUpperCase( (char) c));

 }

 public void write(char buf[], int off, int len) {

  for (int i = 0;i < len;i++) {

   write(buf[off + i]);

  }

 }

 public void write(String s, int off, int len) {

  for (int i = 0;i < len;i++) {

   write(s.charAt(off + i));

  }

 }

}

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

 try {

  filterChain.doFilter(request, new UCaseResponse((HttpServletResponse)(response)));

 }catch(Exception sx) {

  filterConfig.getServletContext().log(sx.getMessage());

}

  该示例使用HttpServletResponseWrapper技术,它是对HttpServletResponse的包装,其实就是装饰(decorate)设计模式的应用.这个例子能够工作的关键是UCaseResponse和UCaseWriter类,它实现了对每个要输出的字符都转成了大写后再写入实际的输出流的功能。

  4、体系架构的实现

  实现一个管道和过滤器一般要注意以下几个方面:

  把系统任务分成一系列处理阶段。

  根据管道和过滤器的设计方案,必须把系统处理的任务分割成相应独立的任务,如日志,数据转化,安全认证等。这样每个阶段仅依赖其前一阶段的输出。通过数据流将所有阶段相连起来。并且你可以进行替换每个步骤,或者可以调整它们之间的顺序,以产生新的结果.如petstore中的编码转化Filter和安全Filter,分成两个独立的处理阶段。

  定义沿每个管道传输的数据格式。

  我们知道每个过滤器,定义一个统一格式以获得最大的灵活性,因为它使过滤器的重组变得容易。如:每个过滤器的方法是doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)它们的参数是必须相同的。

  决定如何实现每个管道连接

  Filter过滤器的连接是推得方式来实现的.前一个过滤器主动的调用filterChain.doFilter(request, response);来实现转向下一个过滤器。

  设计和实现过滤器

  设计每个Filter具有独立的功能,如编码转化,安全校验,等功能.并且每个Fliter都应该在实现javax.servlet.Filter接口。

  建立处理流水线

  过滤器的部署是在Web.xml中进行配置,描述过滤器的实现类以及它们的map关系,来确定它们的顺序。

  其他应用实例

  1、JBOSS

  如果大家对EJB了解,应该知道客户调用EJB实际上并不是直接引用EJB实例(ejb instance).它通过容器来截获客户端的请求,然后按照EJB描述符做些许多相应的工作如,安全校验,事务的处理,线程并发处理等.这样就可以使开发人员仅关心自己的业务逻辑,而不需对复杂的基础服务进行实现.使开发人员从繁琐的工作中解脱出来.集中精力处理自己的业务逻辑,它的结构图如下:

 

500){this.resized=true;this.style.width=500;}" align=center vspace=1 border=1>

 

  笔者有幸阅读了JBOSS的源码,分析了Jboss的EJB容器的实现. EJB的容器通过许多拦截器(Inteceptor)来实现,每个拦截器处理一定的功能,一个处理结束后转发给下一个拦截器,最后一个拦截器才把真正调用EJB的实例.其中它的EntityBean 容器的拦截器的结构如下:

 

500){this.resized=true;this.style.width=500;}" align=center vspace=1 border=1>

 

  我们看其中的log拦截器

public class LogInterceptor extends AbstractInterceptor{

 

public Object invoke(Invocation invocation)

throws Exception

{

 boolean trace = log.isTraceEnabled();

 // Log call details

 if (callLogging)

 {

  ......进行log的处理

 }

 //处理结束,把请求转发给下一个拦截器

 return getNext().invoke(invocation);

}

  这些拦截器配置在standardjboss.xml文件中,如下:

<container-interceptors>

 

 <interceptor>org.jboss.ejb.plugins.LogInterceptor</interceptor>

 <interceptor>org.jboss.ejb.plugins.SecurityInterceptor</interceptor>

 <interceptor>org.jboss.ejb.plugins.TxInterceptorCMT</interceptor>

 <interceptor metricsEnabled="true">org.jboss.ejb.plugins.MetricsInterceptor</interceptor>

 <interceptor>org.jboss.ejb.plugins.EntityLockInterceptor</interceptor>

 <interceptor>org.jboss.ejb.plugins.EntityInstanceInterceptor</interceptor>

 <interceptor>org.jboss.resource.connectionmanager.CachedConnectionInterceptor</interceptor>

 <interceptor>org.jboss.ejb.plugins.EntitySynchronizationInterceptor</interceptor>

 <interceptor>org.jboss.ejb.plugins.cmp.jdbc.JDBCRelationInterceptor</interceptor>

</container-interceptors>

  这就是Jboss容器架构最巧妙的地方,最初这个架构就是由天才少年Rickard Oberg提出的.其实这个架构就应用我们讨论的管道和过滤器模式,其实每个拦截器就是一个过滤器,使用该模式给Jboss带来了如下的好处:

  使系统的架构更容易理解,因为每个过滤器完成单一的功能。

  使系统更加模块化,有利于系统的模块重用和扩展,如果系统想增加某种功能只需增加一个实现Interceptor接口的拦截器,然后配置在standardjboss.xml文件中即可。

  使系统的容易进行错误处理,如果在一个拦截器中发现错误(error)或者异常(exception),只需返回即可.

  2、AXIS

  无独有偶,同样在Axis上也应用了管道和过滤器模式.Aixs是apache开源的webservice实现服务器。简单的说,axis就是处理Message,它首先截获客户端的请求,然后转发到真正的实现业务逻辑上处理客户端的请求,在这之前经过一系列的handler处理.它的结构很像EJB容器.其实就是管道和过滤器模式的应用,Handler就是过滤器.它的处理顺序主要考虑两个方面一个是部署描述符(deployment configuration )另一个就是是客户端还是服务器端。Handler处理的对象是MessageContext它的由3个重要的部分组成,一是一个request Message,一个是response message,还有许多属性。

  我们经研究源码分析,在服务器端,有一个Transport Listener 它监听客户端的请求, 可以通过多种协议,一旦有客户请求,它将按照协议的规范把数据解析生成生成一个Message对象,然后把它设置到MessageContext,然后调用一系列的Handler进行处理。

  其结构图如下:

 

500){this.resized=true;this.style.width=500;}" align=center vspace=1 border=1>

 

  相关设计模式

  在使用管道和过滤器模式时,一般会使用以下的GOF设计模式。

  1、职责链模式(Chain Of Responsibility)

  职责链设计模式的意图就是使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。其实管道和过滤器模式就是职责链模式的抽象,把它应用到软件体系架构中。

  2、 命令模式(Command)

  命令模式的意图将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。在管道和过滤器模式中每个过滤器一般使用命令模式,把请求封装成一个命令进行处理。

  3、装饰模式(Decorator)

  装饰模式的意图就是动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

  在管道和过滤器模式中,在每个过滤器中经常需要对请求进行动态的增加功能,或者修改请求的内容,这时一般会使用装饰模式.如Servlet filter的javax.servlet.http.HttpServletRequestWrapper, javax.servlet.http.HttpServletResponseWrapper就是装饰模式的应用.

  总结

  本文讨论了管道和过滤器模式的解决方案,以及它的优缺点.然后以J2EE规范的Servlet Filter为例详细介绍了怎样应用该模式,同时简单的介绍了在Jboss,Axis中的应用。

分享到:
评论
2 楼 Joo 2008-07-31  
Servlet Filter的缺点在于不能脱离Servlet API的独立的实用AOP
1 楼 Run 2008-07-05  
好文!好文!

相关推荐

    j2ee过滤器Filter使用详解(实例)

    本文将深入解析J2EE过滤器Filter的使用方法,并通过实例来阐述其工作原理。 过滤器在J2EE环境中扮演着预处理和后处理的角色,它可以拦截进入和离开Web应用程序的请求和响应,对数据进行处理或验证,从而提供诸如...

    spring cloud-zuul的Filter使用详解

    Spring Cloud Zuul 的 Filter 使用详解 Spring Cloud Zuul 的 Filter 是 Zuul 网关中的一种机制,允许开发者 intercept 和处理 requests 的过程。Filter 的使用可以实现安全控制、日志记录、性能监控等功能。本文将...

    Filter的使用详解

    Filter的使用详解

    SpringBoot拦截器Filter的使用方法详解

    然后需要在SpringBoot应用中配置Filter,可以通过实现WebMvcConfigurer接口并重写addFilters方法,或者使用@ServletComponentScan注解来自动注册带有@WebFilter注解的类。 在SpringBoot中,过滤器经常用于请求日志...

    css filter滤镜详解

    CSS 滤镜详解 CSS 滤镜是一种可以改变 HTML 元素的视觉效果的技术,通过使用滤镜,可以实现各种特殊效果,如透明度、模糊、阴影、翻转、光效等。本文将详细介绍 CSS 滤镜的常用方法和浏览器兼容问题。 一、透明度...

    ethereal filter使用

    ### Ethereal Filter 使用详解 #### 一、简介 在网络安全分析和故障排查过程中,抓包工具扮演着极其重要的角色。Ethereal(现已更名为Wireshark)是一款功能强大的网络协议分析器,它允许用户捕获并浏览网络上的...

    Java_Filter过滤机制详解.doc

    ### Java Filter过滤机制详解 #### 一、什么是Filter Filter技术是Servlet 2.3版本中新引入的一个功能,它的主要作用在于对Web应用中的请求和响应进行预处理和后处理。Filter本身并不是一个Servlet,因此它不能...

    web.xml 中的listener、 filter、servlet 加载顺序及其详解.doc

    Web.xml 中的 listener、filter、servlet 加载顺序及其详解 在 Web 应用程序中,web.xml 文件扮演着非常重要的角色,它定义了 Web 应用的结构和配置。其中,listener、filter、servlet 是三个非常重要的概念,它们...

    servlet+filter+listener 详解

    Servlet、Filter、Listener 详解 Servlet 是运行在服务器上的小程序,它可以使任何 Java 应用程序、浏览器或任何设备。Servlet 的客户端可以提出请求并获得该请求的响应。Servlet 在初始化后即驻留内存中,因此每次...

    5.5 CSS3中filter属性详解|模糊效果和filter|canvas项目综合实战|Canvas图形、动画、游戏开发从入门到精通全系列课程

    5.5_CSS3中filter属性详解|模糊效果和filter|canvas项目综合实战|Canvas图形、动画、游戏开发从入门

    Filter过滤机制详解

    过滤器的原理解析,以及使用代码实例

    Zend Framework过滤器Zend_Filter用法详解

    例如,在给定的文件内容中,演示了如何使用Zend_Filter组件中的Zend_Filter_StringToLower过滤器类。Zend_Filter_StringToLower类可以将输入的字符串转换为全部小写字母。使用方法是在PHP脚本中首先引入需要的过滤器...

    网页滤镜详解 filter

    ### 网页滤镜详解:filter 在网页设计与开发过程中,为了增强用户体验和页面美观度,开发者经常需要对页面中的元素应用各种效果。其中,“滤镜”(filter)是一种非常实用且强大的工具,它能够改变页面元素的视觉...

    Informatica Filter Transformation组件 详解

    在实际应用中,Filter Transformation还可以与其他转换如Aggregator、Joiner等配合使用,以实现更复杂的数据处理需求。比如,可以在先进行数据聚合后再过滤,或者在JOIN操作后去除不满足条件的记录,以确保数据质量...

    Java_Filter过滤机制详解.

    Java Filter过滤机制是Java Servlet技术中的一个重要组成部分,它在Servlet 2.3版本中被引入,为Web应用程序提供了强大的预处理和后处理能力。Filter不是一个可以直接生成响应的Servlet,而是作为一个中间层,可以在...

    OpenCV filter2D函数详解示例程序源代码

    接下来,我们将分别探讨如何使用filter2D实现图像处理的三种常见操作: **1. 图像锐化** 锐化通常是通过增强图像的边缘和高频细节来实现的。这可以通过应用一个负 Laplacian 核来实现,例如,3x3的核 `[0, -1, 0; ...

    ethereal的使用详解

    在Linux系统中, 1992年Lawrence Berkeley Lab的Steven McCanne和Van Jacobson提出了包过滤器的一种的实现,BPF(BSD Packet Filter)。Libpcap是一个基于BPF的开放源码的捕包函数库。现有的大部分Linux捕包系统都是...

    springsecurity使用配置详解

    3. **过滤器链(Filter Chain)**: Spring Security通过一系列过滤器实现其安全功能。主要的过滤器有: - `ChannelProcessingFilter`:处理HTTP和HTTPS请求。 - `SecurityContextPersistenceFilter`:在请求之间...

    filter wiz pro使用

    **Filter Wiz Pro详解** Filter Wiz Pro是一款专业级别的图像处理软件,专为摄影爱好者和专业人士设计,提供了丰富的滤镜效果和图像编辑功能。这款软件以其直观的操作界面和强大的后期处理能力,在数字图像处理领域...

Global site tag (gtag.js) - Google Analytics