3

我正在使用 RestEasy 3.0.2,它是第一个 JAX-RS 2 实现之一,并在 Tomcat 7 中运行我的应用程序。我还通过 WELD 在我的应用程序中使用注入,它通过其 CDI 适配器与 RestEasy 集成。到目前为止一切正常。

现在,我编写了一个 ContainerRequestFilter 的实现,用于在传入请求到达资源之前对其进行身份验证。JAX-RS 标准规定,对于每个资源和每个其他使用 @Provider 注释进行注释的 JAX-RS 组件,都可以进行注入。

这是我的过滤器实现的简化版本:

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {

    @Inject
    AuthenticationProvider authenticationProvider;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        authenticationProvider.authenticate(requestContext);
    }
}

注意:AuthenticationProvider@RequestScoped

通常,此解决方案有效。正在注入组件,并且正在按预期处理请求。

但我仍然怀疑过滤器的生活范围。如果它是应用程序范围的,那么这显然会导致确定性测试无法发现的“有趣”并发问题。

我查看了各种文档、指南和示例,但我发现没有一个使用过滤器注入或说明过滤器范围。

4

3 回答 3

6

对于 RestEasy,答案在有关 CDI 集成的 RestEasy 文档中给出:

默认情况下,未显式定义范围的 CDI bean 是 @Dependent 范围的。这个伪作用域意味着 bean 适应注入它的 bean 的生命周期。普通范围(请求、会话、应用程序)更适合 JAX-RS 组件,因为它们明确指定组件的生命周期边界。因此,resteasy-cdi 模块通过以下方式更改默认范围:

如果 JAX-RS 根资源未显式定义范围,则将其绑定到请求范围。

如果 JAX-RS Provider 或 javax.ws.rs.Application 子类未显式定义范围,则它将绑定到 Application 范围。

因此,使用 @Provider 注释的 JAX-RS 过滤器是 @ApplicationScoped。

该文档还说,JAX-RS 提供程序可以通过将适当的注释与任何范围相关联。所以一般来说,可以自定义 JAX-RS 过滤器的范围。

重要的是要注意将@RequestScoped 对象注入@ApplicationScoped 过滤器是安全的。这是因为 CDI 不注入对实际对象的引用,而是注入代理。当在代理上调用一个方法时,该对象的一个​​单独实例将用于幕后的每个请求。

这里是相应的WELD 文档

4.9. 客户代理

注入 bean 的客户端通常不持有对 bean 实例的直接引用,除非 bean 是依赖对象(作用域 @Dependent)。

想象一下,绑定到应用程序范围的 bean 持有对绑定到请求范围的 bean 的直接引用。应用程序范围的 bean 在许多不同的请求之间共享。但是,每个请求都应该看到请求范围 bean 的不同实例——当前实例!

...

因此,除非 bean 具有默认范围 @Dependent,否则容器必须通过代理对象间接对 bean 的所有注入引用。此客户端代理负责确保接收方法调用的 bean 实例是与当前上下文相关联的实例。客户端代理还允许绑定到上下文(例如会话上下文)的 bean 序列化到磁盘,而无需递归序列化其他注入的 bean。

我使用以下代码来验证这一点(假设entityManager在示例中生成为@RequestScoped):

@Provider
public class OtherTestFilter implements ContainerRequestFilter {

    @Inject
    EntityManager entityManager;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        Session session =  (Session) entityManager.getDelegate();
        System.out.println(session.hashCode());
    }
} 

这为过滤器处理的每个请求提供了不同的会话哈希值。所以理论和实践在这里匹配。

于 2013-07-28T18:54:24.927 回答
0

它的定义方式看起来像是 DependentScoped。唯一的另一种可能性是静默 RequestScoped,但这不太可能。

于 2013-07-28T00:48:25.237 回答
0

JAX-RS 2 过滤器有什么范围?

默认情况下,过滤器等提供程序是单例的。


文件说什么

Application文档中:

资源类实例的默认生命周期是每个请求。提供者(直接注册或通过功能注册)的默认生命周期是单例。

来自JAX-RS 规范

默认情况下,为每个 JAX-RS 应用程序实例化每个提供程序类的单个实例。首先调用构造函数,然后注入任何请求的依赖项,然后可以多次(同时)调用适当的提供程序方法,最后使对象可用于垃圾回收。

JAX-RS 规范还提到了以下关于 CDI 集成的内容:

提供者和Application子类必须是单例或使用应用程序范围。

于 2018-06-25T15:41:23.073 回答