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

Chr*_*s B 2 jax-rs java-ee resteasy cdi

我正在使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:AuthenticationProvider@RequestScoped.

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

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

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

Chr*_*s B 5

对于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());
    }
} 
Run Code Online (Sandbox Code Playgroud)

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