Tomcat servlet中的ThreadLocal

时间:2012-08-10 23:08:46

标签: java session tomcat thread-local-storage

我遇到了一个问题,我的生产系统中出现了异常,但我真的没有关于是谁造成这些异常的信息。该人的用户名存储为其tomcat会话中的变量,我可以使用doPostdoGet方法访问该变量,但除非我将该信息作为参数传递给我的每个业务对象,我无权访问会话。出于显而易见的原因,我想将用户名添加到日志消息中,以便我知道发生了什么。

所以我的解决方案是做这样的事情

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”的确切问题,我仍然愿意接受其他解决方案,这些解决方案可以优雅地访问会话变量以进行日志记录。我也对我的解决方案的潜在缺陷进行评论。我有一个业务问题要解决,我没有嫁给任何一个解决方案。我只是想知道是谁在我的产品系统中引起异常:)

1 个答案:

答案 0 :(得分:2)

是的,tomcat使用ThreadPool概念,这意味着线程正在被重用,因此你建议“你的线程本地保留值”,

我建议的替代方案可能是

  1. 在完成后清理线程,在视图控制器中的某个位置

  2. 编写请求过滤器并启动过滤器清理所有内容并推送新值, 并将其分配给您服务器上的每个网址格式

  3. 对于您所遵循的方法,而不是在类中保存某些值, 将请求存储在Thread Local中,然后使用请求使用自制的util类从会话中提取值,该类获取请求然后返回所需的值,这样您就可以节省在Thread中保存会话并获取值,但请确保你每次都添加新鲜并在完成后清理请求(使用第二个选项)。