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
方法, 从而实现权限的控制, 关键词的过滤等功能.
参考