2019独角兽企业重金招聘Python工程师标准>>>

一 回顾

控制台有如下打印:

过滤器1执行前
过滤器2执行前
过滤器3执行前
过滤器3执行后
过滤器2执行后
过滤器1执行后

很明显这是使用了三个过滤器。并且每个过滤器都执行了doFilter方法,并且在doFilter方法的执行前后都打印了一句话。所以才会有上述现象。

总结一下过滤器特点:

①第一个过滤器一定会执行。

②下个过滤器能否执行取决于上一个过滤器是否放行。所谓的放行就是调用doFilter方法。

③所有的过滤器都会以链条的形式存在,如果最后一个过滤器得不到执行。那么被拦截的目标(Servlet)也不会得到执行。

二 想法和实现

这里有两个、也只有两个核心的概念:过滤器链和过滤器。两者的关系是容器和元素之间的包含关系。

过滤器链是个容器,可以将它理解称一个数组、集合都没问题。过滤器就是一个类。

到这里,我们可以画出一张图。

这张图对于过滤器理解工作原理来说是没问题的。绿色的√表示过滤器放行,红色的×表示得不到执行的机会。然而要想知道具体实现的细节。我们需要变动一下,

别忘了控制台打印出来的文字是:嵌套的,是嵌套的,嵌套的!!!!

嵌套:意味着递归!

所以正确的过滤器链的执行流程应该是"回型"结构的。像这样:

现在我们把问题模型给简化,把和过滤器不相关的,不重要的东西全部丢掉。

我们定义如下几个接口:

public interface FilterChain {public void execute();
}
public interface Filter {public void doFilter(FilterChain chain);
}

再定义一下几个过滤器实现类

public class FilterImpl1 implements Filter{@Overridepublic void doFilter(FilterChain chain) {System.out.println("过滤器1执行前");chain.execute();System.out.println("过滤器1执行后");}
}
public class FilterImpl2 implements Filter{@Overridepublic void doFilter(FilterChain chain) {System.out.println("过滤器2执行前");chain.execute();System.out.println("过滤器2执行后");}
}
public class FilterImpl3 implements Filter{@Overridepublic void doFilter(FilterChain chain) {System.out.println("过滤器3执行前");chain.execute();System.out.println("过滤器3执行后");}
}

假设配置的执行顺序是1-->2-->3。如何才能实现本文开头提到的控制台的嵌套打印效果呢?

如果说把过滤器比作多米诺骨牌,那么谁来推倒第一张牌?过滤器链的实现类。

谁来负责连续推倒下一张牌?  表面上看是由开发者在doFilter中是否调用chain.execute();决定。然而

最终开发者调用的是过滤器链的execute方法。所以到这里,我们可以得出,过滤器链要实现的功能如下:

1 保存所有的过滤器对象。

2 在execute方法中,取出下一个过滤器对象。执行doFilter方法。实现递归。

这样就能确保,如果开发者在当前过滤器的doFilter方法中不手动调用chain.execute();方法。那么拦截的目标是一定不会执行。并且下一个过滤器也一定不会得到执行

到这里,思路其实已经很明了了。最关键的代码在FilterChain的实现类的中。也就是我们需要记录是否还有下一个过滤器。

这里提供两种实现方式:计数器方式和移除方式。

计数器方式实现的过滤器链:

public class FilterChainImpl implements FilterChain{List<Filter> listfilter = new ArrayList<Filter>();private int index = 0;public void append(Filter filter){listfilter.add(filter);}private boolean execute_target = false;@Overridepublic void execute() {if(index<listfilter.size()){Filter filter = listfilter.get(index);index++;filter.doFilter(this);} if(index==listfilter.size()){if(execute_target == false){execute_target = true;System.out.println("执行拦截目标的方法");}}}
}

移除方式实现的过滤器链:

public class FilterChainImpl implements FilterChain{LinkedList<Filter> listfilter = new LinkedList<Filter>();public void append(Filter filter){listfilter.add(filter);}@Overridepublic void execute() {if(hasNextFilter())nextFilter().doFilter(this);else{System.out.println("执行目标方法");}}public boolean hasNextFilter(){return listfilter.size() > 0;}public Filter nextFilter(){return listfilter.pop();}
}

测试类:

public class TestFilterDemo {public static void main(String[] args) {FilterChainImpl chain = new FilterChainImpl();chain.append(new FilterImpl1());chain.append(new FilterImpl2());chain.append(new FilterImpl3());chain.execute();}
}

三 完整代码

一共有以下几个类:

Filter  接口。实际中Servlet的过滤器还有其它方法,但是比较简单。这里就不写了。下同。

FilterChain 接口。之前出给出的execute方法。是为了区别于Filter的doFilter方法。只要理解了原理,方法名是什么不重要。

FilterChainImpl1 FilterChain的子类。采用计数器方式实现过滤器链。

FilterChainImpl2 FilterChain的子类。采用移除方式实现过滤器链。

FilterImpl1~FilterImpl3  三个Filter的实现类。

TestFilterDemo 测试来,含有main函数。

request对象和Response对象。这里没有给出来。也不需要给。

public interface Filter {public void doFilter(Request rq,Response rp,FilterChain chain);
}
public interface FilterChain {public void doFilter(Request rq,Response rp);
}
public class FilterImpl1 implements Filter{@Overridepublic void doFilter(Request rq,Response rp,FilterChain chain) {System.out.println("过滤器1执行前");chain.doFilter(rq, rp);System.out.println("过滤器1执行后");}
}
public class FilterImpl2 implements Filter{@Overridepublic void doFilter(Request rq,Response rp,FilterChain chain) {System.out.println("过滤器2执行前");chain.doFilter(rq, rp);System.out.println("过滤器2执行后");}
}
public class FilterImpl3 implements Filter{@Overridepublic void doFilter(Request rq,Response rp,FilterChain chain) {System.out.println("过滤器3执行前");chain.doFilter(rq, rp);System.out.println("过滤器3执行后");}
}
public class FilterChainImpl1 implements FilterChain{private LinkedList<Filter> listfilter = new LinkedList<Filter>();public void append(Filter filter){listfilter.add(filter);}@Overridepublic void doFilter(Request rq,Response rp) {if(hasNextFilter())nextFilter().doFilter(rq,rp,this);else{System.out.println("执行目标方法");}}public boolean hasNextFilter(){return listfilter.size() > 0;}public Filter nextFilter(){return listfilter.pop();}
}
public  class FilterChainImpl2 implements FilterChain{private List<Filter> listfilter = new ArrayList<Filter>();private int index = 0;public void append(Filter filter){listfilter.add(filter);}private boolean execute_target = false;@Overridepublic void doFilter(Request rq,Response rp) {if(index<listfilter.size()){Filter filter = listfilter.get(index);index++;filter.doFilter(rq,rp,this);} if(index==listfilter.size()){if(execute_target == false){execute_target = true;System.out.println("执行拦截目标的方法");}}}
}
public class TestFilterDemo {public static void main(String[] args) {FilterChainImpl1 chain = new FilterChainImpl1();chain.append(new FilterImpl1());chain.append(new FilterImpl2());chain.append(new FilterImpl3());//这里实际会传入rquest和response对象。现在只能不传,但是不影响过滤器的是实现。chain.doFilter(null,null);}
}

转载于:https://my.oschina.net/lightled/blog/1824766

Servlet中过滤器的实现原理(源码实现)相关推荐

  1. SpringBoot中请求映射的原理(源码)

    一.先看一下SpringMVC解析流程 时序图: 二.SpringBoot请求映射原理 SpringBoot跟spring一脉相承,所以直接找DispatcherServlet这个类. 其继承关系如下 ...

  2. idea环境下 servlet配置导致jsp页面显示源码问题

    idea环境下 servlet配置导致jsp页面显示源码问题 今天在做jsp实验(虽然是被废弃的技术但是还是课程要求)过程中遇到了一点令人感到困惑的问题:当使用idea自动生成的web.xml文件配置 ...

  3. netty中的future和promise源码分析(二)

    前面一篇netty中的future和promise源码分析(一)中对future进行了重点分析,接下来讲一讲promise. promise是可写的future,从future的分析中可以发现在其中没 ...

  4. WebRTC[1]-WebRTC中h264解码过程的源码分析

    目录 前言 正文 <WebRTC工作原理精讲>系列-总览_liuzhen007的专栏-CSDN博客_webrtc 原理前言欢迎大家订阅Data-Mining 的<WebRTC工作原理 ...

  5. Unity Fog 原理 源码分析 案例

    Unity Fog 原理 源码分析 案例 效果图 简述 背景知识 clip空间坐标的范围 d3d (near,0), unity remapping to (0,far) 越靠近相机z值越小 open ...

  6. 仿猎豹垃圾清理 实现原理+源码

    仿猎豹垃圾清理(实现原理+源码) 转载请注明出处: 仿猎豹垃圾清理(实现原理+源码) 前几天无意打开猎豹内存大师, 发现它的垃圾清理很强大, 效果也不错, 闲着就研究了下. 不过.. 结果貌似和我想象 ...

  7. 仿猎豹垃圾清理(实现原理+源码)

    仿猎豹垃圾清理(实现原理+源码) 转载请注明出处: 仿猎豹垃圾清理(实现原理+源码) 前几天无意打开猎豹内存大师, 发现它的垃圾清理很强大, 效果也不错, 闲着就研究了下. 不过.. 结果貌似和我想象 ...

  8. 仿iOS猎豹垃圾清理(实现原理+源码)

    转载请注明出处: 仿猎豹垃圾清理(实现原理+源码) 前几天无意打开猎豹内存大师, 发现它的垃圾清理很强大, 效果也不错, 闲着就研究了下. 不过.. 结果貌似和我想象的不太一样.怎么说呢, 听我下文一 ...

  9. Learning to Rank中Pointwise关于PRank算法源码实现

    [学习排序] Learning to Rank中Pointwise关于PRank算法源码实现 标签: 学习排序PRankPointwiseLearning to Rank代码实现 2015-01-28 ...

最新文章

  1. cglib invoke 和 invokeSuper 可用的组合
  2. Noj-589 --糖果
  3. (转)二维平面坐标系-最近点对模板
  4. P3041-[USACO12JAN]Video Game G【AC自动机,dp】
  5. 【转】深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第四节 参数传递对堆栈的影响 2
  6. 【算法刷题2】二叉树的后序遍历
  7. 通过还款计划表监控还款异常
  8. P-GCN:Graph Convolutional Networks for Temporal Action Localization 2019 ICCV
  9. python __main__ __name__ __file__
  10. php关键技术,基于Apache+MySQL+PHP的关键技术分析
  11. drools规则引擎介绍
  12. adguard和adblock哪个好_这可能是最全的广告屏蔽方案了!
  13. 停车场管理系统软件概要设计说明书
  14. nodog+adbyby实现密码认证与视频广…
  15. java 向量 内积_向量内积外积
  16. linux查询ip命令
  17. 吃握手包的电子宠物 - Pwnagotchi开箱教程
  18. 开心网外挂开发之 三
  19. VIVADO生成并导入网表文件
  20. cacti graphs new.php,Cacti /graphs_new.php SQL Injection Vulnerability

热门文章

  1. 在网页中使用react
  2. 移动端适配常用解决方案
  3. 前端判断数据类型的通用方法
  4. python webqq机器人_python模拟开发WebQQ(二)
  5. 【spring data jpa】spring data jpa 中的update 更新字段,如果原字段值为null不处理,不为null则在原来的值上加一段字符串...
  6. .NET平台开发必须掌握的XML知识(二)
  7. [LeetCode] NO.292 Nim Game
  8. 最小二乘法拟合非线性函数及其Matlab/Excel 实现(转)
  9. hdu 5256 序列变换 (LIS变形)
  10. Maven+Mybatis+Spring配置