我有以下问题:
ContainerRequestFilter是一个单身人士,但请阅读:
在第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?,似乎我的测试已经确认了。
但我仍有疑虑。
确认?
答案 0 :(得分:5)
是的,这是安全的。要了解问题,您应该了解范围的工作原理。在任何处理范围(和注入)的框架中,该功能都以类似方式实现。如果对象在单例范围内并且需要注入较小范围内的另一个对象,则通常会注入该对象的代理。当对对象进行调用时,它实际上是对代理的调用。
虽然规范可能没有特别提及HttpServletRequest
,但大多数JAX-RS实现都支持这一点。特别是对于Jersey,如果这不可能(意味着对象不可代理),那么在启动时会收到一条错误消息,例如“不在请求范围内”。原因是在应用启动时创建了ContainerRequestFilter
,并且当时也处理了所有注入。如果HttpServletRequest
不可代理,则无法注入,因为在启动时,没有请求范围上下文。
要确认它不是实际的HttpServletRequest
并且是代理,您可以记录request.getClass()
,您将看到它确实是代理。
如果您不熟悉此模式,可以查看this answer以了解其工作原理。
另见: