gpt4 book ai didi

java - DispatcherServlet 中的 ThreadLocal

转载 作者:行者123 更新时间:2023-11-30 03:04:22 27 4
gpt4 key购买 nike

我有一个带有 javascript UI 的 Spring MVC (v4.1.3) Web 应用程序。我已经实现了一个自定义 DispatcherServlet 并在 web.xml 中配置了相同的内容

UI 向服务器发出的每个请求的 HTTP header 中都会发送一个唯一的屏幕代码。

在我的自定义调度程序 servlet 的 doService 方法中,我捕获 HTTP header 并将该值放入 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 变量中存在同名的 null DTO - 因此,有时当我访问服务层的 ThreadLocal 时,我会得到 null

我需要帮助来理解 DispatcherServlet 中 ThreadLocal 的行为 - 为什么它会在 doService 方法中获取另一个请求的值?

提前致谢。

最佳答案

您的代码很容易出错,并且很难理解为什么您需要自定义 DispatcherServlet。过滤器似乎更适合这项任务。

public class UiCodeFilter extends OncePerRequestFilter {

protected void doFilterInternally(HttpServletRequest req, HttpServletResponse res, FilterChain chain) {
try {
String uiCode = req.getHeader("uiCode");

if ((uiCode != null && !uiCode.trim().isEmpty())) {
UiCodeDto uiCodeDto = new UiCodeDto(uiCode);
UiCodeHolder.set(uiCodeDta);
}
chain.doFilter(req, res);
} finally {
UiCodeHolder.clear(); // Always clear!
}

}
}

UiCodeHolder 有一个 static ThreadLocal 来保存值。

public abstract class UiCodeHolder {
static ThreadLocal<UiCodeDto> current = new ThreadLocal<>()

public void set(UiCodeDto uiCode) {
current.set(uiCode);
}

public UiCodeDta get() {
return current.get();
}

public void clear() {
current.remove(); // for older versions use current.set(null);
}
}

在您的服务中,您现在只需执行 UiContextHolder.get() 即可获取正确的值。 UiCodeFilter 负责设置该值,并在请求结束时再次清除该值以防止泄漏。

这种方法不需要丑陋的反射钩子(Hook),很容易理解,Spring、Hibernate 和类似的框架都使用这种方法。

关于java - DispatcherServlet 中的 ThreadLocal,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35176357/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com