57.3. 在阶段限制拦截器放置
概述
将拦截器放在阶段可能无法足够精细地控制其放置,以确保拦截器正常工作。例如,如果某一拦截器需要使用 SAAJ API 检查消息的 SOAP 标头,则需要在将消息转换为 SAAJ 对象的拦截器后运行。在某些情况下,一个拦截器会消耗另一个拦截器需要的信息的一部分。在这种情况下,开发人员可以提供在拦截器之前必须执行的拦截器列表。开发人员也可以提供拦截器列表,该列表必须在拦截器之后执行。
运行时只能在拦截器的阶段遵从这些列表。如果开发人员将拦截器从早期阶段放置于必须在当前阶段之后必须执行的拦截器,则运行时将忽略请求。
先添加到链中
开发拦截器时会出现一个问题,即拦截器所需的数据并不总是存在。当链中的一个拦截器会消耗以后拦截器所需的消息数据时,会出现这种情况。开发人员可以通过修改其拦截器来控制消耗哪些自定义拦截器,并可能解决这个问题。但是,因为 Apache CXF 使用了很多拦截器,所以开发人员无法修改它们。
另一种解决方案是确保在任何使用自定义拦截器所需消息数据的拦截器之前放置自定义拦截器。最简单的方法是将其放置在早期阶段,但并不总是可能。对于需要放置拦截器时,需要放在一个或多个其他拦截器之前,Apache CXF 的 AbstractPhaseInterceptor
类提供两个 addBefore()
方法。
如 例 57.2 “在其他拦截器前添加拦截器的方法” 所示,使用一个拦截器 id,另一个则使用拦截器 id。您可以进行多个调用来继续将拦截器添加到列表中。
例 57.2. 在其他拦截器前添加拦截器的方法
publicaddBefore
String
i
publicaddBefore
Collection<String>
i
如 例 57.3 “指定必须在当前拦截器之后运行的拦截器列表” 所示,开发人员在自定义拦截器的 Constuctor 中调用 addBefore()
方法。
例 57.3. 指定必须在当前拦截器之后运行的拦截器列表
public class MyPhasedOutInterceptor extends AbstractPhaseInterceptor
{
public MyPhasedOutInterceptor() {
super(Phase.PRE_LOGICAL);
addBefore(HolderOutInterceptor.class.getName());
}
...
}
大多数拦截器都将其类名称用于拦截器 id。
添加到链的后面
拦截器需要的数据的另一个原因是数据没有被放在消息对象中。例如,拦截器可能希望将消息数据用作 SOAP 消息,但如果消息被放入到 SOAP 消息前,它将无法正常工作。开发人员可以通过修改其拦截器来控制消耗哪些自定义拦截器,并可能解决这个问题。但是,因为 Apache CXF 使用了很多拦截器,所以开发人员无法修改它们。
另一种解决方案是确保将自定义拦截器放在拦截器或拦截器后,它会生成自定义拦截器所需的消息数据。最简单的方法是将其放置在后续的阶段,但并不总是可能。AbstractPhaseInterceptor
类为当一个或者其它拦截器后需要放置拦截器时,提供两个 addAfter()
方法。
如 例 57.4 “其他拦截器后添加拦截器的方法” 所示,一种方法采用单个拦截器 id,另一个方法取一组拦截器 ID。您可以进行多个调用来继续将拦截器添加到列表中。
例 57.4. 其他拦截器后添加拦截器的方法
publicaddAfter
String
i
publicaddAfter
Collection<String>
i
如 例 57.5 “指定必须在当前拦截器前运行的拦截器列表” 所示,开发人员在自定义拦截器的 Constuctor 中调用 addAfter()
方法。
例 57.5. 指定必须在当前拦截器前运行的拦截器列表
public class MyPhasedOutInterceptor extends AbstractPhaseInterceptor
{
public MyPhasedOutInterceptor() {
super(Phase.PRE_LOGICAL);
addAfter(StartingOutInterceptor.class.getName());
}
...
}
大多数拦截器都将其类名称用于拦截器 id。