2016-11-24 51 views
0

的我有两个请求,过滤器和一个请求拦截如下:订购JAX-RS过滤器和拦截器

@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-RS Web服务。以下是一个示例Web服务方法。

@POST 
@RequestLogger 
@RequestChecker 
@OracleSessionChecker 
@Consumes(MediaType.APPLICATION_JSON) 
@Produces(MediaType.APPLICATION_JSON) 
@Path("Logout") 
public Response logout(@Context HttpServletRequest request, Parameters inputs) { 
    ... 
} 

从给定的优先次序,我认为,为了使过滤器/拦截器被称为将是: LogRequestFilterCheckRequestInterceptorCheckOracleSessionFilter

但他们被称为的实际顺序是: LogRequestFilterCheckOracleSessionFilter,CheckRequestInterceptor

为什么CheckRequestInterceptor最后被称为最后一个,即使其优先级为200,处于中间?

我该如何让它们按照我想要的顺序调用(即,LogRequestFilterCheckRequestInterceptorCheckOracleSessionFilter)?

在此先感谢。

回答

0

所有的RequestFilters都是在任何RequestInterceptors(然后根据它们的优先级执行)之前根据它们的优先级执行的。

我能想到的最简单的解释是,如果你有一个文件夹中的以下文件:

F-100 
F-300 
I-200 

I-200不F-300来之前(前300即使200),因为' F在'我'之前被排序。

0

不能混合过滤器和拦截器执行顺序,看Jersey Documentation

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

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

  1. 客户端请求而被调用:具有连接实体POST请求是建立在客户端上和调用。
  2. ClientRequestFilters:客户端请求过滤器在客户端上执行,他们操纵请求标头。
  3. Client WriterInterceptor:由于请求包含实体,因此在执行MessageBodyWriter之前执行在客户端上注册的writer拦截器。它用GZipOutputStream包装实体输出流。
  4. 客户端MessageBodyWriter:在客户端执行消息主体编写器,将实体序列化为新的GZipOutput流。该数据流将数据压缩并发送到“电线”。
  5. 服务器:服务器收到请求。实体的数据是压缩的,这意味着从实体输入流的纯读取将返回压缩数据。
  6. 服务器预匹配ContainerRequestFilters:ContainerRequestFilters被执行,可以操纵资源方法匹配过程。
  7. 服务器:匹配:资源方法匹配完成。
  8. 服务器:post-matching ContainerRequestFilters:ContainerRequestFilters post匹配过滤器被执行。这包括执行所有全局过滤器(不带名称绑定)并过滤名称绑定到匹配的方法。
  9. Server ReaderInterceptor:读取器拦截器在服务器上执行。 GZIPReaderInterceptor将输入流(来自“wire”的流)封装到GZipInputStream中,并将其设置为上下文。
  10. 服务器MessageBodyReader:服务器消息正文阅读器被执行,它从新的GZipInputStream反序列化实体(从上下文获取)。这意味着读者将读取解压缩的数据,而不是来自“电线”的压缩数据。
  11. 执行服务器资源方法:将反序列化的实体对象作为参数传递给匹配的资源方法。该方法将此实体作为响应实体返回。
  12. 服务器ContainerResponseFilters被执行:响应过滤器在服务器上执行并且他们操作响应头。这包括所有全局绑定过滤器(不带名称绑定)和所有过滤器名称绑定到资源方法。
  13. Server WriterInterceptor:在服务器上执行。它用新的GZIPOuptutStream包装原始输出流。原始流是“进入线路”(来自底层服务器容器的响应的输出流)的流。
  14. 服务器MessageBodyWriter:消息正文编写器在服务器上执行,将实体序列化为GZIPOutputStream。该流压缩数据并将其写入原始流,该原始流将该压缩数据发送回客户端。
  15. 客户端收到响应:响应包含压缩的实体数据。
  16. 客户端ClientResponseFilters:客户端响应过滤器被执行,他们操纵响应头。
  17. 返回客户端响应:从请求调用中返回javax.ws.rs.core.Response。
  18. 客户端代码调用response.readEntity():读取实体在客户端上执行以从响应中提取实体。
  19. Client ReaderInterceptor:调用readEntity(Class)时执行客户端阅读器拦截器。拦截器用GZIPInputStream包装实体输入流。这将解压缩来自原始输入流的数据。
  20. 客户端MessageBodyReaders:调用客户端消息体读取器,它从GZIPInputStream中读取解压缩的数据并对实体进行反序列化。
  21. 客户端:实体从readEntity()返回。

值得一提的是,在上面的场景中,只有当实体存在时才调用读写器拦截器(当没有实体被写入时将实体流包装起来没有意义)。消息体读者和作者也有同样的行为。如上所述,拦截器在消息正文读写器之前执行,作为其执行的一部分,并且可以在读取/写入实体之前封装输入/输出流。在邮件正文读者/作者之前没有运行拦截器的情况也有例外,但上述情况并非如此。例如,当使用内部缓冲从客户端响应多次读取实体时会发生这种情况。然后数据只被拦截一次并保持在缓冲区中'解码'。