我遇到了一个问题,即我的生产系统中出现异常,但我真的没有关于谁导致它们的好信息。该人的用户名作为变量存储在他们的 tomcat 会话中,显然我可以在我的doPost
ordoGet
方法中访问它,但除非我将该信息作为参数传递给我的每个业务对象,否则我无权访问会话. 出于显而易见的原因,我想将用户名添加到日志消息中,这样我就知道发生了什么。
所以我的解决方案是做这样的事情
public class ExceptionUtil {
private ExceptionUtil() { } // no instantiation
private static final ThreadLocal<String> local = new ThreadLocal<String>();
public static void set(String user) { local.set(user); }
public static String get() { return local.get(); }
}
然后在我的帖子/获取中,我可以做到这一点
String username = request.getSession().getAttribute("username");
ExceptionUtil.set(username);
然后在我的例外情况下,我可能会这样做(人为的,不好的做法示例)
catch(SQLException e) {
logger.error(ExceptionUtil.get() + " did something dumb in sql", e);
throw e;
}
我关心的唯一问题是 Tomcat 将如何管理我的线程。如果他们保留线程怎么办?他们会坚持吗?ThreadLocal 值是否也会持续存在?如果我将整个 Session 存储在 ThreadLocal 中而不仅仅是一个字符串,那将是一个严重的内存泄漏可能性。这也意味着如果有人忘记重新设置(或忘记在完成后清除)用户名/会话在一个持续存在多个请求的线程上,那里可能有陈旧的数据。
称我为愤世嫉俗者,但我不想依赖程序员(甚至,尤其是我自己!)不要忘记为程序的正确性做事。如果我可以对我的代码进行白痴验证,我愿意。这意味着更好地了解 Tomcat 将如何使用线程。
因此,单句形式的问题:
如果我在 Tomcat (7.0.27) 上运行的 web 应用程序中使用 ThreadLocal,我是否会冒 Thread 被用于多个请求的风险,并且来自先前请求的数据被持久化?
我应该指出,即使他们没有回答“Tomcat/ThreadLocal 恶作剧”的确切问题,我也愿意接受其他解决方案,这些解决方案允许我优雅地访问会话变量以进行日志记录。我也愿意就我的解决方案的潜在缺陷发表评论。我有一个业务问题要解决,而且我不接受任何一种解决方案。我只想知道是谁一直在我的产品系统上造成异常:)