我遇到了一个问题,我的生产系统中出现了异常,但我真的没有关于是谁造成这些异常的信息。该人的用户名存储为其tomcat会话中的变量,我可以使用doPost
或doGet
方法访问该变量,但除非我将该信息作为参数传递给我的每个业务对象,我无权访问会话。出于显而易见的原因,我想将用户名添加到日志消息中,以便我知道发生了什么。
所以我的解决方案是做这样的事情
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中而不仅仅是一个String,那将是一个严重的内存泄漏漏洞。这也意味着如果有人忘记在多个请求持久存在的线程上重新设置(或忘记清除完成时)用户名/会话,那么可能存在陈旧数据。
打电话给我愤世嫉俗,但我不想依赖程序员(甚至,特别是我自己!)不要忘记为程序的正确性做事。如果我可以防止我的代码,我想。这意味着要更好地了解Tomcat将如何使用线程。
所以,单句形式的问题:
如果我在Tomcat(7.0.27)上运行的webapp中使用ThreadLocal,我会运行吗? 线程被用于多个请求以及使用它的风险 来自先前请求的数据是否被保留?
我应该注意到,即使他们没有回答“Tomcat / ThreadLocal shenanigans”的确切问题,我仍然愿意接受其他解决方案,这些解决方案可以优雅地访问会话变量以进行日志记录。我也对我的解决方案的潜在缺陷进行评论。我有一个业务问题要解决,我没有嫁给任何一个解决方案。我只是想知道是谁在我的产品系统中引起异常:)
答案 0 :(得分:2)
是的,tomcat使用ThreadPool概念,这意味着线程正在被重用,因此你建议“你的线程本地保留值”,
我建议的替代方案可能是在完成后清理线程,在视图控制器中的某个位置
编写请求过滤器并启动过滤器清理所有内容并推送新值, 并将其分配给您服务器上的每个网址格式。
对于您所遵循的方法,而不是在类中保存某些值, 将请求存储在Thread Local中,然后使用请求使用自制的util类从会话中提取值,该类获取请求然后返回所需的值,这样您就可以节省在Thread中保存会话并获取值,但请确保你每次都添加新鲜并在完成后清理请求(使用第二个选项)。