你能用 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>
(或带有自定义DaoException
的ExceptionMapper<DaoException>
)并在那里或ContainerResponseFilter
中处理它,因为ExceptionMapper<?>
处理所有异常。
在transaction.begin()
之前,检查事务的当前状态,并在需要时回滚。
这两个选项都有问题。
-
我发现
ExceptionMapper<Throwable>
过于宽泛,而 ExceptionMapper<DaoException>
可能会遗漏一些其他异常,再次导致事务未清理。
在下一个请求时回滚事务可能需要很长时间,可能会导致其他事务出现锁定问题。
所以在阅读了您的问题后,我目前在想:
使用ContainerRequestFilter
启动事务(结合@NameBinding
注释构造)。
使用ContainerResponseFilter
提交事务(如果资源方法尚未关闭它)。
使用Filter
确保事务已关闭,如果没有,则回滚。
【讨论】:
“ExceptionMapper 太宽泛”是什么意思?如果您只是在 ExceptionMapperExceptionMapper<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