最近又被一个连环坑坑惨了,我踩的坑是与 Spring MVC 的线程模型有关的。
我们的系统现在有两个 war 包,分别部署在不同的 JBoss 上,第一个是互联网可访问的,叫 front 吧,第二个是在防火墙之后的,只能通过 front 来访问,叫 backend,是可以访问数据库的。
front 通过 Hessian 调用 backend 的服务。
现在有个需求要求 backend 记录互联网用户的 IP 和其他一些参数,接口太多,不可能每个方法再添加参数,由于 Hessian 也运行是在 HTTP 上的,所以我想在 Hessian 的 HTTP 请求头里把这些需要的参数传过去。
根据 debug,Hessian 采用的是 JDK 的 HessianURLConnectionFactory
来创建连接,处理 HTTP 请求,所以我就扩展了它的方法 public HessianConnection open(URL url) throws IOException
,在里面把参数放到请求头里。由于要取的是客户端实际 IP 等信息,所以还需要获取客户端的请求 HttpServletRequest
,刚好 Spring MVC 里面有个 RequestContextHolder
工具,持有了 HttpServletRequest
。然后就有了下面这行代码:HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
。坑就挖成了。
点开 RequestContextHolder.getRequestAttributes()
方法来看看:
public static RequestAttributes getRequestAttributes() {
RequestAttributes attributes = requestAttributesHolder.get();
if (attributes == null) {
attributes = inheritableRequestAttributesHolder.get();
}
return attributes;
}
requestAttributesHolder
是这样的:
private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<RequestAttributes>("Request attributes");
NamedThreadLocal
是这样定义的: public class NamedThreadLocal<T> extends ThreadLocal<T> {
。
也就是说这个请求是跟线程绑定的,在别的线程是获取不到的。
其他的坑是这样的:
在 front 有个地方用了异步去调用 backend,其实是根本没必要用异步的(因为当前线程发出请求后是在等待响应的);而这个异步调用在测试环境时没有启用,被开关切去走另一个同步的分支,而生产环境确是必须走这个异步分支的。
欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。