@Context返回Proxy而不是HttpServletRequest(代理范围内没有线程本地值) [英] @Context returns Proxy instead of HttpServletRequest (No thread local value in scope for proxy)

查看:78
本文介绍了@Context返回Proxy而不是HttpServletRequest(代理范围内没有线程本地值)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a bit of a problem with understanding why @Context dependency injection returns collection of $Proxy(random number) instances instead of HttpServletRequest or HttpServletResponse.

我正在使用Glassfish 3.1.2.2和它的Jersey(Jersey:1.11.1)版本,并且我的应用程序是作为EAR应用程序构建的.

I am using Glassfish 3.1.2.2 with it's version of Jersey(Jersey: 1.11.1) and my app is built as EAR application.

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

I have simple @Remote interface where I annotate my methods and REST services work without any problems, but the moment I try to access HttpServletRequest information it just causes problems.

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

I have annotated private fields in my session bean:

@Context
private HttpServletRequest request;
@Context
private HttpServletResponse response;

并还创建了方法签名,以将@Context包含为参数集:

And also created method signature to include @Context as set of parameters:

@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类型.

When I try and debug the method just after an entry I can see that global request and response objects are null where local method instances are of $ProxyXXX type.

问题是我无法访问(或不确定如何)这些对象.根据网络上的教程,它们应该对我可用,但是当我尝试访问这些内容时,就会抛出该错误:

The problem is I can't access (or I'm not sure how) these objects. According to tutorials on the web they should be available to me, but the moment I try to access these, this is being thrown:

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)

This is how I am trying to call these (in this example I simply call getContextPath)

@Override
public Response authenticate(String username, String password, HttpServletRequest request, HttpServletResponse response) {

    System.out.println("just a test: " + request.getContextPath());

我在这里想念什么?有没有人遇到过类似的问题?

What am I missing here? Has anyone experienced similar problem?

格雷格

推荐答案

要了解此问题,您需要了解范围的工作原理.为了描述发生了什么,这里有一个例子.假设你有这个

To understand this problem you need to understand how scopes work. To describe what happens, here is an example. Suppose you have this

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

    @Context
    private HttpServletRequest request;
}

这种情况带来的问题是,每个请求都会生成一个HttpServletRequest,但是资源类仅创建一次,因为它是一个单例,因此最初没有HttpServletRequest可以插入到单例中已创建.

The problem that this situation poses is that an HttpServletRequest is generated for each request, but the resource class is created only once, as it's a singleton, so there is initially no HttpServletRequest to inject into the singleton when it is created.

为解决此问题,Jersey注入了代理.所以从概念上讲,结果更像是

To solve this problem, Jersey injects a proxy. So conceptually, the result is more like

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

    @Context
    private ProxyHttpServletRequest proxyRequest;
}

当请求进入时,实际的HttpServletRequest会放在范围上下文中的ThreadLocal 中.这不是确切的实现,但是您可以将范围上下文想象为类似

When the request comes in, the actual HttpServletRequest is put into a ThreadLocal in a scope context. This is not an exact implementation but you can imagine a scope context as something like

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

    public static HttpServletRequest get() { .. }
    public static void setRequest(HttpServletRequest request) { .. }
}

当请求进入时,HttpServletRequest被设置为上下文.当在SomeResource内部对HttpServletRequest进行调用时,实际上是在代理对象上进行的,该代理对象从ThreadLocal获取请求并转发调用.从概念上讲,您可以想象它看起来像

When the request comes in the HttpServletRequest is set into the context. And when calls are made to the HttpServletRequest inside the SomeResource, it is actually made on the proxy object which grabs the request from the ThreadLocal and forwards the calls. Conceptually, you imagine it to look something like

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将注入实际的请求而不是代理.

The difference with this is that the request is no longer injected into a field, so no proxy is required. The HttpServletRequest is only needed when the call to the method is made. So Jersey will inject the actual request and not a proxy.

仅需注意的是,这种模式并不只针对球衣.任何涉及DI和范围的框架,在尝试将范围较小的对象注入范围较大的对象时,都将使用类似的代理模式.

Just to note, that this pattern is not specific to just Jersey. Any framework were DI and scopes are involved, will use a similar proxy pattern when trying to inject lesser scope objects into wider scope objects.

致OP:现在,这不是您的确切问题.上面的答案更有可能使大多数对代理有疑问的人受益.

To OP: Now this is not your exact problem. The above answer will more likely benefit the majority of people who have questions about the proxy.

在您的情况下,您说要尝试将HttpServletRequest注入到@Remote EJB中.一件事,我什至不知道那是不可能的.我的猜测是EJB引擎从不设置ThreadLocal.因此,当Jersey尝试调用它时,上下文中没有任何内容.

In your case, you said you are trying to inject the HttpServletRequest into a @Remote EJB. For one thing I didn't even know that was or is possible. My guess is that the EJB engine never sets the ThreadLocal. So when Jersey tries to call it, there is nothing in the context.

@Context注释适用于JAX-RS组件,不适用于EJB.我个人不知道如何将HttpServletRequest注入到EJB中,因为我对EJB的使用不多.因此,面对您的确切问题的任何人都将需要搜索那个的方法.但是就像我说的那样,我认为搜寻此问题的人并不多.我想他们只是想知道为什么请求是代理而不是实际请求.因此,此答案更适合他们.

The @Context annotation is meant for JAX-RS components, not for EJBs. I personally, don't know how to inject an HttpServletRequest into an EJBs, as I don't work much with EJBs. So anyone facing your exact problem, will need to search for how to do that. But like I said, I don't think that is the majority of people who search this question. I imagine they are simply wondering why the request is a proxy instead of the actual request. So this answer is more geared towards them.

这篇关于@Context返回Proxy而不是HttpServletRequest(代理范围内没有线程本地值)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆