Java JAX-RS过滤器和拦截器的顺序

Java JAX-RS过滤器和拦截器的顺序,java,jax-rs,Java,Jax Rs,我有两个请求过滤器和一个请求拦截器,如下所示: @Provider @RequestLogger @Priority(100) public class LogRequestFilter implements ContainerRequestFilter { ... } @Provider @OracleSessionChecker @Priority(300) public class CheckOracleSessionFilter implements ContainerRequ

我有两个请求过滤器和一个请求拦截器,如下所示:

@Provider
@RequestLogger
@Priority(100)
public class LogRequestFilter implements ContainerRequestFilter {
    ...
}

@Provider
@OracleSessionChecker
@Priority(300)
public class CheckOracleSessionFilter implements ContainerRequestFilter {
    ...
}

@Provider
@RequestChecker
@Priority(200)
public class CheckRequestInterceptor implements ReaderInterceptor {
    ...
}
我有使用这些过滤器和拦截器的JAX-RSWeb服务。下面是一个示例web服务方法

@POST
@RequestLogger
@RequestChecker
@OracleSessionChecker
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("Logout")
public Response logout(@Context HttpServletRequest request, Parameters inputs) {
    ...
}
根据给出的优先级,我认为过滤器/拦截器的调用顺序是:
LogRequestFilter
CheckRequestInterceptor
CheckOracleSessionFilter

但它们被称为的实际顺序是:
LogRequestFilter
CheckOracleSessionFilter
CheckRequestInterceptor

<>为什么“代码>检查请求截获器< /代码>被调用最后,即使它的优先级,200,在中间?

如何使它们按我想要的顺序被调用(即,
LogRequestFilter
CheckRequestInterceptor
CheckOracleSessionFilter


提前感谢。

您不能混合使用筛选器和侦听器执行顺序,请参阅:

10.4。过滤器和拦截器执行顺序

让我们仔细看看过滤器和拦截器的执行上下文。以下步骤描述了JAX-RS客户机向服务器发出POST请求的场景。服务器接收一个实体,并用相同的实体发送一个响应。GZIP读写器拦截器在客户端和服务器上注册。此外,在客户端和服务器上注册过滤器,这些过滤器会更改请求和响应的标题

  • 调用的客户机请求:在客户机上构建并调用带有附加实体的POST请求
  • ClientRequestFilters:客户机请求筛选器在客户机上执行,并操纵请求头
  • 客户端WriterInterceptor:由于请求包含实体,因此在执行MessageBodyWriter之前,将执行在客户端注册的writer侦听器。它用GZipOutputStream包装实体输出流
  • 客户端MessageBodyWriter:在将实体序列化到新GZipOutput流的客户端上执行消息体编写器。该流将数据压缩并发送到“wire”
  • 服务器:服务器接收请求。实体的数据被压缩,这意味着从实体输入流的纯读取将返回压缩数据
  • 服务器预匹配ContainerRequestFilters:执行ContainerRequestFilters,可以操作资源方法匹配过程
  • 服务器:匹配:已完成资源方法匹配
  • 服务器:后匹配ContainerRequestFilters:执行ContainerRequestFilters后匹配筛选器。这包括执行所有全局筛选器(不带名称绑定)和绑定到匹配方法的筛选器名称
  • 服务器ReaderInterceptor:在服务器上执行读取器侦听器。GZIPReaderInterceptor将输入流(来自“wire”的流)包装到GZipInputStream中,并将其设置为上下文
  • Server MessageBodyReader:执行Server MessageBodyReader,并从新的GZipInputStream(从上下文获取)反序列化实体。这意味着读取器将从“wire”读取解压缩数据,而不是压缩数据
  • 执行服务器资源方法:反序列化的实体对象作为参数传递给匹配的资源方法。该方法将此实体作为响应实体返回
  • 执行Server ContainerResponseFilters:在服务器上执行响应筛选器,它们操作响应头。这包括所有全局绑定筛选器(不带名称绑定)和所有绑定到资源方法的筛选器名称
  • 服务器WriterInterceptor:在服务器上执行。它用一个新的gzipoupoutstream包装原始输出流。原始流是“连接”的流(底层服务器容器响应的输出流)
  • 服务器MessageBodyWriter:消息正文编写器在服务器上执行,该服务器将实体序列化到GziOutputStream中。此流压缩数据并将其写入原始流,原始流将此压缩数据发送回客户端
  • 客户端接收响应:响应包含压缩的实体数据
  • 客户端ClientResponseFilters:执行客户端响应筛选器,并操纵响应头
  • 返回客户端响应:从请求调用返回javax.ws.rs.core.response
  • 客户端代码调用response.readEntity():在客户端上执行read entity以从响应中提取实体
  • 客户端ReaderInterceptor:调用readEntity(类)时执行客户端读取器侦听器。拦截器用GZIPInputStream包装实体输入流。这将从原始输入流中解压缩数据
  • 客户端消息体读取器:调用客户端消息体读取器,从GZIPInputStream读取解压缩数据并反序列化实体
  • 客户端:实体从readEntity()返回
  • 值得一提的是,在上面的场景中,只有实体存在时才会调用读写器拦截器(当没有实体将被写入时,包装实体流是没有意义的)。信息主体读者和作者也有同样的行为。如上所述,作为执行的一部分,拦截器在消息体读/写器之前执行,它们可以在实体读/写之前包装输入/输出流。当拦截器未在消息体读取器/写入器之前运行时会出现异常,但上述简单场景并非如此。例如,当使用内部缓冲从客户端响应多次读取实体时,就会发生这种情况。然后数据只被截获一次,并在缓冲区中保持“解码”


    所有requestfilter都是根据优先级在任何requestinterceptor之前执行的
    F-100
    F-300
    I-200