Filter
Filter是servlet规范中定义的java web组件, 在所有支持java web的容器中都可以使用Filter和FilterChain密不可分,Filter可以实现依次调用正是因为有了FilterChain
Filter接口
|
|
FilterChain接口
|
|
Tomcat filter源码
创建FilterChain
|
|
每次请求过来都会创建一个过滤器链(filterChain),并把待执行的servlet对象存放到过滤器链中。对于每个url,对应的filter个数都是不固定的,filterchain需要保存每个请求所对应的一个filter数组,以及调用到的filter的position,以便继续向下调用filter
|
|
创建顺序:
- 把要执行的
servlet存放到过滤器链中。 - 如果没有配置过滤器则
return一个空的过滤器链(只包含上面设置的servlet)。 - 如果配置
url-pattern过滤器,则把匹配的过滤器加入到过滤器链中 - 如果配置
servlet-name过滤器,则把匹配的过滤器加入到过滤器链中
注意: filterChain.addFilter()顺序与web.xml中定义的Filter顺序一致,所以过滤器的执行顺序是按定义的上下顺序决定的。
过滤器链执行
|
|
如果servlet和过滤器链都不为空,则开始调用过滤器链的doFilter()方法
|
|
ApplicationFilterChain.internalDoFilter()
|
|
FilterChain调用Filter后,Filter再执行FilterChain.doFilter(request, response),可见FilterChain与Filter构成回调模式(这个也是与Spring Interceptor不同点, Interceptor基于java反射机制)
案例
假设下面的Filter就是调用链中的最后一个Filter
|
|
- 在
LogFilter调用chain.doFilter之后就跳过了if语句从而调用了真正的servlet, 然后internalDoFilter方法就结束(出栈)了, 紧接着就是调用Log.info("after")了, 然后LogFilter的doFilter就结束了(也出栈了), 紧接着就是internalDoFilter中filter.doFilter(request, response, this)的结束然后return, 然后就是调用上一个filter的chain.doFilter()之后的代码, 以此类推. Filter调用链的实现其实就是一个方法调用链的过程. 刚开始,Filter Chain每调用一个Filter.doFilter()方法就是向方法调用栈中进行压栈操作(代码上的体现就是执行Filter.doFilter之前的代码), 当Filter全部调用完成之后就调用真正处理请求的servlet, 然后由方法调用链自动进行出栈操作(代码上的体现就是执行Filter.doFilter之后的代码), 从而完成整个Filter的调用链. 因为Filter功能实现实际上就是利用了方法的压栈出栈, 所以可以在调用chain.doFilter之前将方法返回, 让容器不在调用servlet方法, 从而实现权限的控制, 关键词的过滤等功能.
参考