Java @上下文返回代理而不是HttpServletRequest(代理的作用域中没有线程本地值)

Java @上下文返回代理而不是HttpServletRequest(代理的作用域中没有线程本地值),java,dependency-injection,jersey,glassfish-3,Java,Dependency Injection,Jersey,Glassfish 3,我在理解为什么依赖项注入返回$Proxy(随机数)实例集合而不是HttpServletRequest或HttpServletResponse时有点问题 我正在使用Glassfish 3.1.2.2及其Jersey版本(Jersey:1.11.1),我的应用程序是作为EAR应用程序构建的 我有一个简单的@Remote接口,我在其中注释我的方法,REST服务可以正常工作,但当我试图访问HttpServletRequest信息时,它只会导致问题 我在会话bean中注释了私有字段: @Context p

我在理解为什么依赖项注入返回$Proxy(随机数)实例集合而不是HttpServletRequest或HttpServletResponse时有点问题

我正在使用Glassfish 3.1.2.2及其Jersey版本(Jersey:1.11.1),我的应用程序是作为EAR应用程序构建的

我有一个简单的@Remote接口,我在其中注释我的方法,REST服务可以正常工作,但当我试图访问HttpServletRequest信息时,它只会导致问题

我在会话bean中注释了私有字段:

@Context
private HttpServletRequest request;
@Context
private HttpServletResponse response;
还创建了方法签名,将@Context作为一组参数包括在内:

@POST
@Path("authenticate")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public Response authenticate(@FormParam("username") String username, @FormParam("password") String password, @Context HttpServletRequest request, @Context HttpServletResponse response); 
当我尝试在一个条目之后调试该方法时,我可以看到全局请求和响应对象为null,而本地方法实例为$ProxyXXX类型

问题是我无法访问(或者我不确定如何访问)这些对象。根据web上的教程,我应该可以使用它们,但当我尝试访问它们时,就会抛出以下命令:

WARNING: StandardWrapperValve[RestDataService]: PWC1406: Servlet.service() for servlet RestDataService threw exception
java.lang.IllegalStateException: No thread local value in scope for proxy of class $Proxy245
    at com.sun.jersey.server.impl.ThreadLocalInvoker.invoke(ThreadLocalInvoker.java:93)
    at $Proxy245.getContextPath(Unknown Source)
这就是我试图调用它们的方式(在本例中,我只调用getContextPath)

我错过了什么?有没有人经历过类似的问题


格雷格

不是同一个问题,我得到了适当的会话对象和上下文。这样对我来说很好

   public login login(request Request,@Context MessageContext context) {

                 HttpServletRequest httpServletRequest = context
                              .getHttpServletRequest();

}要理解这个问题,您需要了解作用域是如何工作的。为了描述发生了什么,这里有一个例子。假设你有这个

@Singleton
@Path("..")
public class SomeResource {

    @Context
    private HttpServletRequest request;
}
这种情况带来的问题是为每个请求生成一个
HttpServletRequest
,但是资源类只创建一次,因为它是一个单例,所以在创建单例时,最初没有
HttpServletRequest
注入单例

为了解决这个问题,Jersey注入了一个代理。所以从概念上讲,结果更像

@Singleton
@Path("..")
public class SomeResource {

    @Context
    private ProxyHttpServletRequest proxyRequest;
}
当请求传入时,实际的
HttpServletRequest
被放入作用域上下文中的
ThreadLocal
。这不是一个精确的实现,但您可以将范围上下文想象为

public class RequestScopeContext {
    private static final ThreadLocal<HttpServletReqest> request
            = new ThreadLocal<>();

    public static HttpServletRequest get() { .. }
    public static void setRequest(HttpServletRequest request) { .. }
}
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和作用域的框架,在尝试将较小范围的对象注入较大范围的对象时,都将使用类似的代理模式


到OP:现在这不是你的问题。上述答案更有可能使大多数对代理有疑问的人受益

在您的例子中,您说您正在尝试将
HttpServletRequest
注入到
@Remote
EJB中。首先,我甚至不知道这是或是可能的。我的猜测是EJB引擎从不设置
ThreadLocal
。因此,当Jersey试图调用它时,上下文中没有任何内容


@Context
注释用于JAX-RS组件,而不是EJB。我个人不知道如何将
HttpServletRequest
注入EJB,因为我不太会使用EJB。因此,任何人面对你的确切问题,都需要寻找如何做到这一点。但正如我所说,我不认为这是大多数人谁搜索这个问题。我想他们只是想知道为什么请求是代理而不是实际请求。所以这个答案更适合他们。

我解决了一些相同的问题,你可以参考-->
@Singleton
@Path("..")
public class SomeResource {

    @GET
    public Response get(@Context HttpServletRequest request) {
        ...
    }
}