JAX-RS(Jersey)ExceptionMapper-将上下文注入到静态/单例类中-它有效,但为什么



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

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

文档说这确实是由设计支持的功能实现的,并且是通过使用"代理"实现的。

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

谢谢,
AG

附言:这是测试代码:

@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;
    }
}

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

- http://localhost/app/one
- http://localhost/app/two

我的程序打印:

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

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

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

最新更新