前言
Filter
的功能之一就是预处理客户请求,而Tomcat
阀是对Catalina
容器接收到的HTTP
请求进行预处理.
过滤器实在Servlet
规范中提出来的,因此适用于所有的Servlet
容器,而Tomcat
阀是Tomcat
转悠的,不能用于Tomcat
以外的其他Servlet
容器.
简介
阀可以加入到3种容器中:
/
和
.
所有的阀都实现了org.apache.catalina.Valve
,它有如下几个方法:
public Valve getNext();
public void setNext(Valve valve);
public void backgroundProcess();
public void invoke(Request request, Response response)
throws IOException, ServletException;
public boolean isAsyncSupported();
其中最重要的是invoke()
,它的官方JavaDoc
描述如下:
根据该阀门的要求执行请求处理。
单个Valve可以按指定顺序执行以下操作:
检查或修改指定的请求和响应的属性。
检查指定
Request
的属性,完全生成相应的Response
,并将控制权返回给调用者。检查指定的请求和响应的属性,包装这两个对象中的一个或两个,以补充其功能,然后将其传递。
如果未生成相应的
Response
(并且未返回控件),请通过执行getNext()
。invoke()
来调用管道中的下一个Valve
(如果存在):getNext().invoke(request, response);
检查但不修改最终响应的属性(该响应是由随后调用的
Valve
或Container
创建的)。阀门绝对不能做以下任何事情:
- 更改已经用于指导此请求的处理控制流程的请求属性(例如,尝试更改标准实施中应从连接到主机或上下文的管道将请求发送到的虚拟主机)。
- 创建完成的响应并将此请求和响应传递到管道中的下一个阀门。
- 除非与请求完全相关联,否则请消耗与请求相关联的输入流中的字节,除非它完全生成了响应,或者在传递请求之前将其包装。
- 在
getNext()
。invoke()
方法返回后,修改Response
包含的HTTP
标头。- 在
getNext()
。invoke()
方法返回后,对与指定的Response
关联的输出流执行任何操作。
属性
的基本表示形式是:
这里所列的其他属性
根据具体的Valve
实现类而定,它定义了哪些成员变量这里就可以对应设置属性,不过都是简单类型,比如字符串或数字等.
内置阀
内置阀有很多,不过常用的也就几种,具体参考官网,这里给出的是9.0
版本链接,不同版本在URL
中替换即可.
常用内置阀:
- 客户访问日志阀,这个是默认开启的,在
server.xml/
中,会生成访问日志,位置在$CATALINA_HOME/logs
文件夹下 - 远程地址过滤器, 定义哪些地址可以访问,哪些予以禁止
- 远程主机过滤器, 定义哪些主机可以访问,哪些予以禁止
- 客户请求记录器
位置
若要使得阀门生效,需要将其放在合适的位置上.不同的位置代表不同的作用域.根据作用范围从大到小排列:
- 放在
server.xml
的Engine
元素下 - 放在
server.xml
的
元素下 - 放在
context
中,关于context
的位置不唯一的情况,这里推荐$project_base_dir/src/main/META-INF/context.xml
,具体原因见JavaWeb-Tomcat_Context
最常见的是第3种情况,可以根据项目需要自定义阀.
其次是第2种情况,比如默认开启的客户访问日志阀(``AccessLogValve`)就定义在这个位置.
第1种不太常用,不过视情况而定.
自定义
自定义阀需要满足几个条件:
- 实现类的包名必须是
org.apache.catalina.valves
- 必须将自定义阀所在
jar
包放在$CATALINA_HOME/lib
路径下,这两条是由Tomcat
的ClassLoader
决定的.否则会报错ClassNotFoundException
. - 实现
org.apache.catalina.Valve
接口,一般是继承org.apache.catalina.valves.ValveBase
类并重写invoke
方法即可.
问题记录
-
默认开启了访问日志阀,为什么确始终看不见相应的日志文件?
刚开始接触
Valve
,查看了server.xml
中的确开启了客户访问日志的阀,可是始终看不到logs
目录下出现相应的日志文件,经过研究发现是调用命令的问题,因为我用的是IDEA
中的集成方式启动和部署war
项目到Tomcat
,而这种方式调用的是catalina.sh run
命令,这种模式导致日志被重定向到控制台,所以需要部署后自行调用catalina.sh start
或startup.sh
就可以了.