要理解这个问题,您需要了解作用域的工作原理。为了描述发生的情况,这里有一个例子。假设你有这个
@Singleton
@Path("..")
public class SomeResource {
@Context
private HttpServletRequest request;
}
这种情况带来的问题是HttpServletRequest
为每个请求生成,但资源类仅创建一次,因为它是单例,所以最初没有HttpServletRequest
在创建单例时注入到单例中。
为了解决这个问题,Jersey 注入了一个代理。所以从概念上讲,结果更像是
@Singleton
@Path("..")
public class SomeResource {
@Context
private ProxyHttpServletRequest proxyRequest;
}
当请求进来时,实际的HttpServletRequest
被放入一个ThreadLocal
in a 范围上下文。这不是一个精确的实现,但您可以将范围上下文想象为类似的东西
public class RequestScopeContext {
private static final ThreadLocal<HttpServletReqest> request
= new ThreadLocal<>();
public static HttpServletRequest get() { .. }
public static void setRequest(HttpServletRequest request) { .. }
}
当请求到达时HttpServletRequest
被设置到上下文中。当拨打电话时HttpServletRequest
在 - 的里面SomeResource
,它实际上是在代理对象上进行的,该对象从代理对象中获取请求ThreadLocal
并转接电话。从概念上讲,你想象它看起来像
class ProxyHttpServletRequest {
public String getContextPath() {
HttpServletRequest request = RequestScopeContext.get();
return request.getContextPath();
}
}
现在假设我们有这个
@Singleton
@Path("..")
public class SomeResource {
@GET
public Response get(@Context HttpServletRequest request) {
...
}
}
与此不同的是,请求不再注入到字段中,因此不需要代理。这HttpServletRequest
仅当调用该方法时才需要。因此 Jersey 将注入实际请求而不是代理。
请注意,这种模式不仅仅适用于泽西岛。任何涉及 DI 和范围的框架,在尝试将较小范围的对象注入到更广泛范围的对象中时,都会使用类似的代理模式。
To OP:现在这不是你的确切问题。上述答案更有可能使大多数对代理有疑问的人受益。
就您而言,您说您正在尝试注入HttpServletRequest
into a @Remote
EJB。一方面我什至不知道那是或is可能的。我的猜测是 EJB 引擎永远不会设置ThreadLocal
。因此,当 Jersey 尝试调用它时,上下文中没有任何内容。
The @Context
注释适用于 JAX-RS 组件,而不是 EJB。我个人不知道如何注入HttpServletRequest
进入 EJB,因为我很少使用 EJB。因此,任何面临您确切问题的人都需要寻找如何做that。但就像我说的,我认为搜索这个问题的人并不是大多数。我想他们只是想知道为什么请求是代理而不是实际请求。所以这个答案更适合他们。