你能用 JAX-RS/Jersey 做传统的 Servlet 过滤吗?

Posted

技术标签:

【中文标题】你能用 JAX-RS/Jersey 做传统的 Servlet 过滤吗?【英文标题】:Can you do traditional Servlet Filtering with JAX-RS/Jersey? 【发布时间】:2013-05-07 21:53:44 【问题描述】:

假设您有一个过滤器,它启动数据库事务、处理请求,然后尝试提交事务。

doFilter(...) 
    ...
    transaction.begin();
    filterChain.doFilter(request, response);
    transaction.commit();

使用 Jersey,有一些问题:

    使用过滤器,Jersey Servlet 容器在执行返回到您的过滤器之前提交/刷新响应。因此,如果提交失败,您不能将返回码修​​改为失败。此外,JAX-RS ExceptionMapper 不会捕获异常。

    使用 ContainerRequestFilter/ContainerResponseFilter。

    public ContainerRequest filter(ContainerRequest request) ... 公共 ContainerResponse 过滤器(ContainerRequest 请求,ContainerResponse 响应) ...

这允许异常冒泡到 ExceptionMapper,但将逻辑拆分为 2 个单独的方法/接口。问题是如果有一个没有映射到响应的异常,ContainerResponseFilter 永远不会被调用,所以你无法清理。

在 JAX-RS 环境中处理此问题的首选方法是什么?有没有办法配置响应的刷新,或者有没有我忽略的类或接口?

【问题讨论】:

您所描述的通常称为“视图中的打开会话”(反)模式。请参阅this SO question 进行讨论。也转向 JBoss (Hibernate/Seam) 进行更多讨论,例如community.jboss.org/docs/DOC-13954 对于“视图”究竟由什么构成肯定存在一些争论,但这只是一个 REST 应用程序。 jax-rs 资源方法是服务层,它们直接使用持久性。响应对象是服务调用的结果。我试图避免在每种方法中都进行事务管理,答案是类似于过滤器的东西,或者我连接 CDI 拦截(如果可以的话,我想在项目的这一点上避免这种情况)。 【参考方案1】:

我也针对 JAX-RS/RESTEasy 应用程序进行了一些研究。在阅读此问题之前我正在考虑的两个选项:

    编写一个ExceptionMapper<Throwable>(或带有自定义DaoExceptionExceptionMapper<DaoException>)并在那里或ContainerResponseFilter 中处理它,因为ExceptionMapper<?> 处理所有异常。 在transaction.begin() 之前,检查事务的当前状态,并在需要时回滚。

这两个选项都有问题。

    我发现 ExceptionMapper<Throwable> 过于宽泛,而 ExceptionMapper<DaoException> 可能会遗漏一些其他异常,再次导致事务未清理。 在下一个请求时回滚事务可能需要很长时间,可能会导致其他事务出现锁定问题。

所以在阅读了您的问题后,我目前在想:

使用ContainerRequestFilter 启动事务(结合@NameBinding 注释构造)。 使用ContainerResponseFilter 提交事务(如果资源方法尚未关闭它)。 使用Filter 确保事务已关闭,如果没有,则回滚。

【讨论】:

“ExceptionMapper 太宽泛”是什么意思?如果您只是在 ExceptionMapper 中检查会话中的活动事务,则可以确定出现问题并回滚。如果没有活动事务,则什么也不做。我看到的问题是,如果 ContainerResponseFilter 中的 transaction.commit() 失败,则必须更改响应对象。不知道如果ContainerResponseFilter中抛出异常会发生什么,它会被ExceptionMapper捕获吗? 太宽泛了,您可能还有ExceptionMapper<SpecificException>。哪个ExceptionMapper<?> 将处理异常?首先是SpecificException,然后是Throwable?还是后者会吞下SpecificException 只会使用最具体的提供者。正如 JAX-RS 2.0 规范所说:When choosing an exception mapping provider to map an exception, an implementation MUST use the provider whose generic type is the nearest superclass of the exception. When a resource class or provider method throws an exception for which there is an exception mapping provider, the matching provider is used to obtain a Response instance.

以上是关于你能用 JAX-RS/Jersey 做传统的 Servlet 过滤吗?的主要内容,如果未能解决你的问题,请参考以下文章

JAX-RS (Jersey 2) - 使用 JSR 250 注释的授权

JAX-RS (jersey) -> Angular.js 通过 REST

检索结果JAX-RS + Jersey + Jackson

JAX-RS Jersey 读取内容类型为“*”的实体

JAX-RS(Jersey 2 实现)内容协商,带有 URL 扩展名 .xml 或 .json

Jax-rs -jersey 跨域请求启用