Java JAX-RS(Jersey)ExceptionMapper-@Context注入到静态/单例类中-它可以工作,但为什么?

Java JAX-RS(Jersey)ExceptionMapper-@Context注入到静态/单例类中-它可以工作,但为什么?,java,rest,jersey,jax-rs,Java,Rest,Jersey,Jax Rs,我有一个实例类,实现ExceptionMapper。它不是一个静态类,但我知道它是一个只创建了一个实例的类(我选中了-构造函数只调用一次) 我的类使用@Context HttpServletRequest,我可以清楚地观察到,当调用ExceptionMapper.toResponse()方法时,@Context'request'参数的值与引发异常的请求相关 这确实是设计支持的特性,并且是通过使用“代理”实现的 我想知道这到底是如何实现的——一个实例如何同时具有不同的成员变量值 谢谢你, 银 注:

我有一个实例类,实现ExceptionMapper。它不是一个静态类,但我知道它是一个只创建了一个实例的类(我选中了-构造函数只调用一次)

我的类使用@Context HttpServletRequest,我可以清楚地观察到,当调用ExceptionMapper.toResponse()方法时,@Context'request'参数的值与引发异常的请求相关

这确实是设计支持的特性,并且是通过使用“代理”实现的

我想知道这到底是如何实现的——一个实例如何同时具有不同的成员变量值

谢谢你,

注:以下是测试代码:

@Provider
public class MyExceptionMapper implements ExceptionMapper<Exception> {

    public MyExceptionMapper() {
        System.out.println("CTOR!!");
    }

    @Context HttpServletRequest req;

    public static boolean done = false;  
    public Response toResponse(Exception ex) {
        if (!done) {
            done = true;
            Thread.sleep(10000);
        }
        System.out.println(req.getRequestURI());
        return null;
    }
}
我的程序打印:

CTOR!
http://localhost/app/one
http://localhost/app/two

实现您观察到的效果的最简单方法是,将注入的
HttpServletRequest
对象实际作为代理对象,即真正的
HttpServletRequest
的线程感知委托。在委托上调用方法时,它们所做的只是查找正确的真实对象(例如,通过线程局部变量),并将调用传递给该对象。这个策略相对来说比较简单,因为它是一个接口,所以我们绝对不必担心字段访问(这对于代理来说有点棘手)


有几种不同的方法可以构造这样的代理对象。特别是,它可以通过直接实现
HttpServletRequest
接口来实现,也可以通过Java(可以为任何接口构造代理)来实现。还有其他更复杂的可能性,比如运行时代码生成,但在这里它们是不必要的。当然,如果直接实现了
HttpServletRequest
,我一点也不会感到惊讶;对于JAX-RS实现来说,它是一个有点重要的类…

尝试将volatile修饰符添加到“done”变量中。它告诉JVM可以跨线程修改该值。如果没有volatile修饰符,每个线程都有一个“done”变量的不同副本,并且可能会导致您经历的副作用。
CTOR!
http://localhost/app/one
http://localhost/app/two