10

我有一个单实例类,实现 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;
    }
}

我的 REST 处理程序方法引发异常,因此当我“并行”执行以下 2 个请求时(上面的睡眠确保第二个请求到达时第一个请求未完成,恕我直言,应修改唯一的“req”字段):

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

我的程序打印:

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

1 回答 1

6

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

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

于 2013-07-20T20:31:44.170 回答