首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Servlet 3规范和ThreadLocal

Servlet 3规范和ThreadLocal
EN

Stack Overflow用户
提问于 2011-02-20 23:21:40
回答 5查看 6.9K关注 0票数 28

据我所知,Servlet 3规范引入了异步处理特性。除其他外,这将意味着同一个线程可以并且将被重用来处理另一个并发的HTTP请求。这并不是革命性的,至少对于以前和NIO合作过的人来说是这样的。

无论如何,这导致了另一件重要的事情:no 作为请求数据的临时存储。因为如果同一个线程突然成为另一个HTTP请求的载体线程,请求-本地数据将暴露在另一个请求中。

所有这些都是我基于阅读文章的推测,我没有时间使用任何Servlet 3实现(Tomcat 7、GlassFish 3.0.X等)。

所以,问题是:

  • 我是否正确地认为,ThreadLocal将不再是保存请求数据的方便的黑客?
  • 曾经使用过Servlet 3实现中的任何一个并尝试使用ThreadLocal来证明上述?
  • 除了在HTTP会话中存储数据之外,还有其他类似的易于访问的黑客您可以提供建议吗?

f 216

编辑:没有误解我。我完全理解危险和ThreadLocal是一个黑客。事实上,我总是建议不要在类似的情况下使用它。然而,不管你信不信由你,线程上下文的使用比你想象的要频繁得多。一个很好的例子是Spring的OpenSessionInViewFilter,根据它的Javadoc:

此过滤器使Hibernate会话通过当前线程可用,事务管理器将自动检测该线程。

这并不是严格意义上的ThreadLocal (还没有检查源代码),但听起来已经令人震惊了。我可以想到更多类似的场景,而丰富的web框架使得这种可能性更大。

简单地说,很多人在这次黑客攻击的基础上建造了他们的沙堡,不管有没有意识。因此,斯蒂芬的回答是可以理解的,但并不完全是我想要的。我想确认是否有人真的尝试过能够再现的失败行为,因此这个问题可以用作其他被同样问题困住的人的参考点。

EN

回答 5

Stack Overflow用户

发布于 2011-02-21 00:00:14

(请注意:我还没有详细阅读Servlet 3规范,所以我不能肯定规范说出了您认为它所做的事情。我只是假设它确实.)

--我是否正确地认为,ThreadLocal将不再是保存请求数据的方便黑客?

使用ThreadLocal总是一种糟糕的方法,因为当一个工作线程完成一个请求而启动另一个请求时,您总是冒着信息泄漏的风险。将内容作为属性存储在ServletRequest对象中总是一个更好的主意。

现在,你有了另一个理由,用“正确”的方式去做。

有没有人玩过Servlet 3的任何一种实现,并试图使用ThreadLocals来证明上面的这些?

这不是正确的方法。它只告诉您在测试的特定情况下特定实现的特定行为。你不能概括。

正确的方法是假设它有时会发生如果规范说它可以.并设计你的网页应用程序来考虑它。

(不要害怕!显然,在这种情况下,默认情况下不会发生这种情况。您的webapp必须显式地启用异步处理功能。如果代码中充斥着线程局部变量,则建议您不要这样做.)

除了在HTTP中存储数据外,还有其他类似的易于访问的黑客您可能会提供建议。

不是的。唯一正确的答案是在ServletRequest或ServletResponse对象中存储特定于请求的数据。即使将它存储在HTTP会话中也可能是错误的,因为对于给定的会话,可以同时激活多个请求。

票数 6
EN

Stack Overflow用户

发布于 2011-03-02 04:02:53

注:黑客紧随其后。使用时要小心,否则就不要使用。

只要您继续了解代码在哪个线程中执行,就没有理由不能安全地使用ThreadLocal。

代码语言:javascript
复制
try {
    tl.set(value);
    doStuffUsingThreadLocal();
} finally {
    tl.remove();
}

这并不是说您的调用堆栈是随机关闭的。见鬼,如果您想在调用堆栈中设置深入的ThreadLocal值,然后进一步使用,您也可以对此进行黑客攻击:

代码语言:javascript
复制
public class Nasty {

    static ThreadLocal<Set<ThreadLocal<?>>> cleanMe = 
        new ThreadLocal<Set<ThreadLocal<?>>>() {
            protected Set<ThreadLocal<?>> initialValue() {
                return new HashSet<ThreadLocal<?>>();
            }
        };

    static void register(ThreadLocal<?> toClean) {
       cleanMe.get().add(toClean);
    }

    static void cleanup()  {
        for(ThreadLocal<?> tl : toClean)
            tl.remove();
        toClean.clear();
    }
}

然后,在设置ThreadLocals时注册它们,并在某个地方使用finally子句进行清理。这都是你不应该做的可耻的傻事。对不起,我写的太晚了。

票数 3
EN

Stack Overflow用户

发布于 2011-03-02 09:56:48

我仍然想知道为什么人们使用腐朽的servlets来实现他们的servlet。我所做的:

  • I有一个基类HttpRequestHandler,它有用于请求、响应的私有字段和一个可以抛出异常的handle()方法,再加上一些实用方法来获取/设置参数、属性等。我很少需要5%-10%的servlet,所以这不是听起来那么多工作。在servlet处理程序中,创建这个类的一个实例,然后忘记servlet。
  • 我可以扩展这个处理程序类,并添加我需要的所有字段和数据。没有庞大的参数列表,没有线程本地黑客,也没有对并发性的担忧。
  • I有一个用于单元测试的实用程序类,它创建了一个具有请求和响应模拟实现的HttpRequestHandler。这样,我就不需要servlet环境来测试我的代码了.

这解决了我所有的问题,因为我可以在init()方法中获得DB会话和其他东西,或者在servlet和真正的处理程序之间插入一个工厂来执行更复杂的事情。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5060823

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档