泽西岛2:过滤器和@Context注入

时间:2015-11-10 14:38:43

标签: jersey-2.0

我有以下问题:

ContainerRequestFilter是一个单身人士,但请阅读:

Jaxrs-2_0 Oracle Spec

在第9.2章中,他们说:

  

上下文特定于特定请求,但某些JAX-RS组件(具有除每个请求之外的生命周期的提供程序和资源类)的实例可能需要支持多个并发请求。当注入第9.2节中列出的类型之一的实例时,提供的实例必须能够为特定请求选择正确的上下文。使用线程本地代理是实现此目的的常用方法。

在9.2节中,没有提到HttpServletRequest。

所以问题是:在并发方面将HttpServletRequest注入自定义ContainRequestFilter是否安全?

我的意思是:

@Provider
@PreMatching
public class AuthenticationFilter implements ContainerRequestFilter {

   @Context private HttpServletRequest request;  

   @Override
   public void filter(ContainerRequestContext requestContext) throws IOException {
    // This is safe because every thread call the method with its requestContext
    String path = requestContext.getUriInfo().getPath(true);

    // Is this safe? The property request is injected by using @Context annotation (see above)
    String toReturn = (String)request.getAttribute(name);

    [...]
}

我在调试模式下对我的IDE做了一些实证测试,用两个不同的浏览器发送两个不同的并发请求,它似乎运行良好;我注意到过滤器的实例是相同的(它是一个单例),但注入的HttpServletRequest在这两种情况下是不同的。

我甚至连这个帖子:How to access wicket session from Jersey-2 request filter?,似乎我的测试已经确认了。

但我仍有疑虑。

确认?

1 个答案:

答案 0 :(得分:5)

是的,这是安全的。要了解问题,您应该了解范围的工作原理。在任何处理范围(和注入)的框架中,该功能都以类似方式实现。如果对象在单例范围内并且需要注入较小范围内的另一个对象,则通常会注入该对象的代理。当对对象进行调用时,它实际上是对代理的调用。

虽然规范可能没有特别提及HttpServletRequest,但大多数JAX-RS实现都支持这一点。特别是对于Jersey,如果这不可能(意味着对象不可代理),那么在启动时会收到一条错误消息,例如“不在请求范围内”。原因是在应用启动时创建了ContainerRequestFilter,并且当时也处理了所有注入。如果HttpServletRequest不可代理,则无法注入,因为在启动时,没有请求范围上下文。

要确认它不是实际的HttpServletRequest并且是代理,您可以记录request.getClass(),您将看到它确实是代理。

如果您不熟悉此模式,可以查看this answer以了解其工作原理。

另见: