JAX-RS2过滤器的作用域是什么



我使用的是RestEasy 3.0.2,它是最早的JAX-RS2实现之一,并在Tomcat7中运行我的应用程序。我还通过WELD在我的应用程序中使用注入,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

一般来说,这个解决方案是有效的。正在按预期注入组件并处理请求。

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

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

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

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

如果JAX-RS根资源没有显式定义作用域,那么它就是绑定到请求范围。

如果JAX-RS提供程序或javax.ws.RS.Application子类没有定义作用域明确地,它绑定到应用程序范围

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

文档还说,JAX-RS提供者可以通过对其进行适当的注释来与任何范围相关联。因此,一般来说,JAX-RS过滤器的范围是可以自定义的。

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

此处为焊接文件:

4.9客户代理

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

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

因此,除非bean具有默认作用域@Dependent,否则容器必须通过代理对象。此客户端代理负责确保接收方法调用的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());
    }
} 

这为过滤器处理的每个请求提供了一个不同的散列值session。所以理论和实践是一致的。

它的定义方式看起来像是DependentScoped。唯一的其他可能性是一个无声的RequestScoped,但可能性不大。

JAX-RS2过滤器有什么作用域?

默认情况下,过滤器等提供程序是singleton


文件说明

来自Application文档:

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

来自JAX-RS规范:

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

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

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

最新更新