我有一个实例类,实现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实现来说,它是一个非常重要的类…