JAX-RS(Jersey)ExceptionMapper - @Context注入静态/单例类 - 它有效,但为什么呢?

Wan*_*All 10 java rest jax-rs jersey

我有一个单实例类,实现了ExceptionMapper.它不是一个静态类,但它是一个我知道只创建单个实例的类(我检查过 - 构造函数只被调用一次).

我的类使用@Context HttpServletRequest,我可以清楚地看到,当调用我的ExceptionMapper.toResponse()方法时,@ Context'request'参数有一个值,该值与抛出异常的请求相关.

该文档说 这确实是由设计支持的功能,并且它是通过使用"代理"来完成的.

我想知道这是如何实现的 - 单个实例如何同时具有不同的成员变量值?

谢谢你,
AG

PS:这是测试代码:

@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的REST处理程序方法抛出异常,所以当我"并行"执行以下2个请求时(上面的睡眠确保当第二个到达时第一个没有完成并且恕我直言应该修改唯一的'req'字段):

- http://localhost/app/one
- http://localhost/app/two
Run Code Online (Sandbox Code Playgroud)

我的程序打印:

CTOR!
http://localhost/app/one
http://localhost/app/two
Run Code Online (Sandbox Code Playgroud)

Don*_*ows 6

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

有几种不同的方法来构造这样的代理对象.特别是,它可以通过直接实现HttpServletRequest接口来完成,或者可以通过Java 通用动态代理机制(可以为任何接口构建代理)更一般地完成.还有其他更复杂的可能性,例如运行时代码生成,但这里不需要它们.OTOH,如果HttpServletRequest直接实施,我不会感到惊讶; 对于JAX-RS实现来说,它是一个有点重要的类...