servlet规范(参见我之前的问题)保证同一个线程将执行所有Filter和相关的Servlet。鉴于此,如果可以选择使用HttpServletRequest.setAttribute
(假设您正确清理),我认为使用ThreadLocal
传递数据没有任何用处。我觉得使用ThreadLocal
有两个好处:类型安全性和更好的性能,因为没有使用字符串键或映射(除了可能通过(非字符串)线程ID进入线程集合)。
有人可以确认我是否正确,以便继续放弃setAttribute
?
答案 0 :(得分:3)
线程本地工作会更好。如果您正在使用JSP / JSF页面或从HttpServletRequest读取的其他Web UI组件,那么您最终必须自己从ThreadLocal中提取信息。 对于大多数网络编程而言,2并不等同。
答案 1 :(得分:3)
以这种方式使用ThreadLocal意味着您依赖某种类型的单例来维护共享状态。最终,这通常被认为是糟糕的设计,因为它有许多缺点,包括难以封装功能,意识到依赖性,以及无法交换(或模拟)功能。
与处理单例中较不常见的ThreadLocal变量提议相比,使用属性或会话的性能开销可能是值得的。但是,这当然取决于您的具体用例和项目。在servlet中使用单例作为维护应用程序状态的方法在某种程度上是常见的,因为难以与servlet共享应用程序状态(难以注入依赖项),但对于那些对象单例对象维护每个用户状态(在EJB之外)是不寻常的)。
如果使用会话或将容器对象设置为属性,则只需通过String(可能是O(1))处理单个提取,然后处理容器类型的单个提取(具有您想要的所有值的特定访问器)。进一步调用代码应该采用适当的参数,尽量避免使用任何类型的全局或单例。
最终,在考虑性能名称中有点不同寻常(虽然聪明)的解决方案之前,请先测试直接实现,看看它的性能是否足够。与在db查询和tcp连接建立上花费的20 + ms相比,这里可能保存的2ns很可能是无关紧要的。
答案 2 :(得分:3)
我建议反对ThreadLocal。
我明白为什么你在考虑它,但我认为你正陷入过早的优化陷阱。 ThreadLocals本质上是全局变量 - 很少是一个好的设计。节省的时间可以忽略不计。我保证这永远不会成为服务器吞吐量的瓶颈。
如果您想开始对某些请求使用异步响应(例如支持长轮询),使用ThreadLocal也可能会给您带来问题,因为线程模型非常不同。
答案 3 :(得分:3)
ThreadLocal是否优于HttpServletRequest.setAttribute(“key”,“value”)?
取决于具体的功能要求。
例如, JSF将FacesContext
存储在ThreadLocal
中。这使您可以访问所有JSF工件,包括HttpServletRequest
执行的代码中的“原始”HttpServletResponse
和FacesServlet
,例如托管bean。大多数其他基于Java的MVC框架都遵循相同的示例。
根据你的评论,
我主要需要将User和EntityManager对象从用户和数据库过滤器传输到Servlet。我还发现这些在进一步的代码中经常出乎意料地需要,我很想在Servlet之外使用它们(即在doGet调用的嵌套代码中)。我觉得有更深层次的代码可能有更好的方法 - 建议吗?
至于我假设这是一个会话属性的User
示例,我宁愿采用与JSF相同的方法。创建ThreadLocal<Context>
,其中Context
是您的自定义包装类,包含对当前HttpServletRequest
的引用,也可能HttpServletResponse
,以便您可以在代码中的任何位置访问它们。如有必要,可提供便捷方法,直接从User
类中获取Context
。
关于EntityManager
示例,您可以采用相同的方法,但我个人不会将其放在相同的 ThreadLocal<Context>
中,而是将其放在另一个 {/ 1>}中。或者,更好的是,只需从服务层中的JNDI获取它,这将允许您对事务进行更细粒度的控制。无论如何,请确保您正确处理提交/关闭。从容器中接管持久性和事务管理应该非常小心。我真的要重新考虑使用现有的和设计良好的API /框架(如EJB / JPA)的厌恶,否则你将冒险完全浪费时间重新发明所有已标准化的API和内容。