首页 > 其他分享 >J2EE开发中Filter的奇妙作用

J2EE开发中Filter的奇妙作用

时间:2023-07-28 18:32:59浏览次数:32  
标签:filter J2EE name -- 奇妙 Filter 过滤器 public


Servlet2.3 Filter

  1、Servlet Filter概述

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

   访问特定资源(Web 页、JSP 页、servlet)时的身份认证
   应用程序级的访问资源的审核和记录
   应用程序范围内对资源的加密访问,它建立在定制的加密方案基础上
   对被访问资源的及时转换, 包括从 servlet 和 JSP 的动态输出
  
  在servlet2.3之前这些功能处理是很难实现的,但是Java Servlet 2.3 规范新增了不少激动人心的功能,其中之一便是过滤器(Filter),其实这就是我们所说的管道和过滤器体系架构在J2EE中的应用实践. 通过使用该模式使得Web Application开发者能够在请求到达Web资源之前截取请求,在处理请求之后修改应答。其结构图如下:


J2EE开发中Filter的奇妙作用_xml

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


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


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


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



J2EE开发中Filter的奇妙作用_xml


  2、Filter链介绍


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



J2EE开发中Filter的奇妙作用_xml


  3、例子


  3.1 简单filter


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


J2EE开发中Filter的奇妙作用_xml



代码:


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的字符串变成大写)。


代码:


er {  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()); }



  该示例使用HttpServletResponseWrapp er技术,它是对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描述符做些许多相应的工作如,安全校验,事务的处理,线程并发处理等.这样就可以使开发人员仅关心自己的业务逻辑,而不需对复杂的基础服务进行实现.使开发人员从繁琐的工作中解脱出来.集中精力处理自己的业务逻辑,它的结构图如下:



J2EE开发中Filter的奇妙作用_xml


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



J2EE开发中Filter的奇妙作用_xml


  我们看其中的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文件中,如下:


代码:


r</interceptor>  <interceptor>org.jboss.resource.connectionmanager.CachedConnectionIntercep     tor</interceptor>  <interceptor>org.jboss.ejb.plugins.EntitySynchronizationInt     erceptor</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进行处理。


  其结构图如下:



J2EE开发中Filter的奇妙作用_xml


   相关设计模式



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


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


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


  2、 命令模式(Command)


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


  3、装饰模式(Decorator)


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


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


   总结



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


标签:filter,J2EE,name,--,奇妙,Filter,过滤器,public
From: https://blog.51cto.com/u_548275/6886096

相关文章

  • Android setColorFilter
    AndroidsetColorFilter详解在Android开发中,我们经常需要对图片进行处理以实现特定的效果。其中,setColorFilter函数是一个非常常用的方法之一,可以用来改变图片的颜色以及应用各种滤镜效果。本文将详细介绍setColorFilter方法的用法和示例代码,帮助读者了解如何使用该方法。setColo......
  • Java 连接redis at java.io.FilterOutputStream.flush(FilterOutputStream.java:1
    了解RedisRedis(REmoteDIctionaryServer)是一个开源的、基于内存的数据结构存储系统,它支持多种数据结构,如字符串、哈希、列表、集合、有序集合等。Redis提供了丰富的功能和高性能的数据操作,使其成为一个流行的数据库和缓存解决方案。Redis提供了多种语言的客户端库,使开发人员......
  • linux netfilter 引发网络不稳定
     记录前因:K8S部署的集群,最近遇到域名解析失败情况,查看coredns日志,没有明显问题。解析报错:connectiontimedout;noserverscouldbereached 重启集群服务,解析没有问题,基本确认跟某个业务服务有关联解决过程: 查看跟踪连接数:sysctlnet.netfilter.nf_conntrack_coun......
  • ABP VNext添加全局认证(如何继承AuthorizeFilter)
    前言目前公司采用的开发框架是ABPVNext微服务框架最近突然发现一个问题,ABP中如果控制器或服务层没有加 Authorize特性的话,则不会走身份认证,且不会认证Token如图: 但是项目已开发大半,一个个去补Authorize特性,工作量比较大,也容易产生遗漏就想着以前做单体应用的时候......
  • GIS应用领域揭秘:探索数字世界中的奇妙之旅
    随着科技的飞速发展,地理信息系统(GIS)作为一种基于地理位置信息的强大工具,在各个领域中的应用愈发广泛。从城市规划到农业发展,从环境保护到医疗健康,GIS的应用越来越深入,为我们带来了许多新奇的发现和意想不到的效益。 GIS在城市规划领域的应用不可忽视。通过收集大量的城市数据,GI......
  • 利用Nginx http_image_filter_module模块来裁剪过大的图片
    http_image_filter_module是nginx提供的集成图片处理模块,支持nginx-0.7.54以后的版本,在网站访问量不是很高磁盘有限不想生成多余的图片文件的前提下可,就可以用它实时缩放图片,旋转图片,验证图片有效性以及获取图片宽高以及图片类型信息,由于是即时计算的结果,所以网站访问量大的话,不建......
  • java拦截Filter和过滤器HandlerInterceptor
    什么是过滤器过滤器Filter是基于Servlet实现,对进入到Servlet的请求拦截。主要用于对字符编码,跨域等问题过滤。如下图:所有的请求和都经过Filter,通过定义Filter,能够对请求进行编码操作。代码是以接口的形式提供:publicinterfaceFilter{defaultvoidinit(FilterConfigfilt......
  • Array方法: indexOf、filter、forEach、map、reduce详解
    [array方法:indexof、filter、foreach、map、reduce详解|FEblog](https://007sair.github.io/2015/08/17/js-Extras/#map)ECMAScript5标准新增了几个数组操作的方法,让我们来看看都是什么:Array.prototype.indexOfArray.prototype.lastIndexOfArray.prototype.everyArray.......
  • javascript中map reduce filter的示例代码
    以下是JavaScript中map、reduce和filter的示例代码:Map(映射)示例代码:Map函数将数组中的每个元素映射为一个新的值,返回一个新的数组。constnumbers=[1,2,3,4,5];//将数组中的每个元素平方constsquaredNumbers=numbers.map(num=>num*num);console.log(square......
  • 修正fpc(lazarus)BufDataSet.Filter使用中文字段名称时过滤无效的Bug
    最近使用fpc(lazarus)BufDataset的Filter遇到中文字段名称时过滤无效的问题,曾尝试将中文字段名加双引号或中括号,但仍然不行。经跟踪Bufdataset源码发现dbf_prsore.pasFilter没正确识别中文引起的,修正这个问题比较简单:打开/fpcsrc/packages/fcl-db/src/dbase/dbf_prsore.pas定位83......