我遇到了一个问题,我的生产系统中出现了异常,但我真的没有关于是谁造成这些异常的信息.该人的用户名存储为其tomcat会话中的变量,我可以在我的doPost或doGet方法中查看,但除非我将该信息作为参数传递给我的每个业务对象,否则我无法访问会议.出于显而易见的原因,我想将用户名添加到日志消息中,以便我知道发生了什么.
所以我的解决方案是做这样的事情
public class ExceptionUtil {
private ExceptionUtil() { } // no instantiation
private static final ThreadLocal local = new ThreadLocal();
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将如何使用线程.
那么,单句形式的问题:
If I use ThreadLocal in a webapp running on Tomcat (7.0.27), do I run
the risk of a Thread being used for multiple requests, and with it
data from a previous request being persisted?
我应该注意到,即使他们没有回答“Tomcat / ThreadLocal shenanigans”的确切问题,我仍然愿意接受替代解决方案,这些解决方案允许我优雅地访问会话变量以进行日志记录.我也对我的解决方案的潜在缺陷进行评论.我有一个业务问题要解决,我没有嫁给任何一个解决方案.我只是想知道谁在我的prod系统上引起异常:)
最佳答案 是的,tomcat使用ThreadPool概念,这意味着线程正在被重用,因此你建议“你的线程本地保留值”,
我建议的替代方案可能是什么
>完成后清理线程,在视图控制器中的某个位置
>编写请求过滤器并开始过滤器清理所有内容并推送新值,
并将此分配给您的服务器上的每个网址模式.
对于您正在遵循的方法而不是在类中保存某些值,
将请求存储在Thread Local中,然后使用请求使用自制的util类从会话中提取值,该类获取请求然后返回所需的值,这样您就可以节省在Thread中保存会话并获取值,但请确保你每次都添加新鲜并在完成后清理请求(使用第二个选项).