【发布时间】:2016-05-12 14:37:09
【问题描述】:
我有一个带有 javascript UI 的 Spring MVC (v4.1.3) Web 应用程序。我已经实现了一个自定义 DispatcherServlet 并在 web.xml 中进行了相同的配置
UI 向服务器发出的每个请求的 HTTP 标头中都会发送一个唯一的屏幕代码。
在我的自定义调度程序 servlet 的 doService 方法中,我捕获 HTTP 标头并将值放入 ThreadLocal dto 变量中。我在服务层访问这个 ThreadLocal 变量来执行一些对所有请求都通用的审计逻辑。
来自 CustomDispatcherServlet 的代码:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
String uiCode = request.getHeader("uiCode");
if ((uiCode != null && !uiCode.trim().isEmpty())) {
UiCodeDto uiCodeDto = new UiCodeDto(uiCode);
final ThreadLocal<UiCodeDto> threadLocalUser = new ThreadLocal<UiCodeDto>();
threadLocalUser.set(uiCodeDto);
}
...
super.doService(request, response);
}
来自服务层的代码:
UiCodeDto temp = ThreadLocalUtil.getUiCodeDto(Thread.currentThread());
从 ThreadLocal 中检索值的 ThreadLocalUtil 代码:
public final class ThreadLocalUtil {
public static UiCodeDto getUiCodeDto(Thread currThread) {
UiCodeDto UiCodeDto = null;
try {
Field threadLocals = Thread.class.getDeclaredField("threadLocals");
threadLocals.setAccessible(true);
Object currentThread = threadLocals.get(currThread);
Field threadLocalsMap = currentThread.getClass().getDeclaredField("table");
threadLocalsMap.setAccessible(true);
threadLocalsMap.setAccessible(true);
Object[] objectKeys = (Object[]) threadLocalsMap.get(currentThread);
for (Object objectKey : objectKeys) {
if (objectKey != null) {
Field objectMap = objectKey.getClass().getDeclaredField("value");
objectMap.setAccessible(true);
Object object = objectMap.get(objectKey);
if (object instanceof UiCodeDto) {
UiCodeDto = (UiCodeDto) object;
break;
}
}
}
} catch (Exception e) {
...
}
return UiCodeDto;
}
}
问题如下—— 1. 我得到屏幕代码的随机值 - 这意味着一些 http 请求 N 的值来自 http 请求 N+1。 2. ThreadLocal 变量中存在同名的空 DTO - 因此,有时当我访问服务层中的 ThreadLocal 时,我得到一个空值
我需要帮助来理解 DispatcherServlet 中 ThreadLocal 的行为 - 为什么它会在 doService 方法中获取另一个请求的值?
提前致谢。
【问题讨论】:
-
因为容器使用线程池来服务请求,因为你只是设置东西而不是清除值。旁边检索值的方式是非常可怕的恕我直言。我也不明白为什么你需要一个自定义的
DispatcherServlet。使用Filter,它使用UiCodeHolder(很像LocaleResolver和朋友的工作)来设置、检索和清除ThreadLocal。 -
添加@M.Deinum 所说的内容。只要有线程池被使用,就不应该使用 ThreadLocal。这会导致内存泄漏。
-
为什么在doservice中使用threadlocal?
标签: java spring spring-mvc thread-local