JAX-RS 2过滤器有哪些范围?

时间:2013-07-27 11:21:17

标签: java-ee jax-rs cdi resteasy

我正在使用RestEasy 3.0.2,这是第一个JAX-RS 2实现之一,并在Tomcat 7中运行我的应用程序。我还通过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

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

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

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

3 个答案:

答案 0 :(得分:5)

对于RestEasy,答案在RestEasy documentation concerning CDI integration

中给出
  

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

     

如果JAX-RS根资源未明确定义范围,则为   绑定到请求范围。

     

如果JAX-RS Provider或javax.ws.rs.Application子类未定义范围   显式地,它绑定到应用程序范围。

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

该文档还说,JAX-RS提供程序可以通过为其添加适当的注释来与任何范围相关联。因此,一般来说,JAX-RS过滤器的范围可以定制。

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

根据WELD documentation

  

4.9。客户代理

     

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

     

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

     

...

     

因此,除非bean具有默认范围@Dependent,否则   容器必须通过a间接所有注入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());
    }
} 

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

  

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

过滤器之类的提供程序默认为单个


文档怎么说

摘自Application文档:

  

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

来自JAX-RS specification

  

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

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

  

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